diff --git a/BUILD.bazel b/BUILD.bazel index fd9ee70aeb..b980d990e8 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -217,6 +217,12 @@ alias( visibility = ["//visibility:public"], ) +alias( + name = "json", + actual = "//src/google/protobuf/json", + visibility = ["//visibility:public"], +) + ################################################################################ # Java support ################################################################################ diff --git a/CHANGES.txt b/CHANGES.txt index 6f5751767a..ff30066758 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -41,14 +41,6 @@ * More thoroughly annotate public generated code in Java lite protocol buffers. * Fixed Bug in proto3 java lite repeated enum fields. Failed to call copyOnWrite before modifying previously built message. Causes modification to already "built" messages that should be immutable. * Fix Java reflection serialization of empty packed fields. - * Refactoring java full runtime to reuse sub-message builders and prepare to - migrate parsing logic from parse constructor to builder. - * Move proto wireformat parsing functionality from the private "parsing - constructor" to the Builder class. - * Change the Lite runtime to prefer merging from the wireformat into mutable - messages rather than building up a new immutable object before merging. This - way results in fewer allocations and copy operations. - * Make message-type extensions merge from wire-format instead of building up instances and merging afterwards. This has much better performance. Python * Changes ordering of printed fields in .pyi files from lexicographic to the same ordering found in the proto descriptor. @@ -58,6 +50,21 @@ Compiler * Print full path name of source .proto file on error +2022-09-29 version 21.7 (C++/Java/Python/PHP/Objective-C/C#/Ruby) + Java + * Refactoring java full runtime to reuse sub-message builders and prepare to + migrate parsing logic from parse constructor to builder. + * Move proto wireformat parsing functionality from the private "parsing + constructor" to the Builder class. + * Change the Lite runtime to prefer merging from the wireformat into mutable + messages rather than building up a new immutable object before merging. This + way results in fewer allocations and copy operations. + * Make message-type extensions merge from wire-format instead of building up + instances and merging afterwards. This has much better performance. + * Fix TextFormat parser to build up recurring (but supposedly not repeated) + sub-messages directly from text rather than building a new sub-message and + merging the fully formed message into the existing field. + 2022-09-13 version 21.6 (C++/Java/Python/PHP/Objective-C/C#/Ruby) C++ diff --git a/Protobuf-C++.podspec b/Protobuf-C++.podspec index 8ab70d04ac..55d6d1b403 100644 --- a/Protobuf-C++.podspec +++ b/Protobuf-C++.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Protobuf-C++' - s.version = '3.21.6' + s.version = '3.21.7' s.summary = 'Protocol Buffers v3 runtime library for C++.' s.homepage = 'https://github.com/google/protobuf' s.license = 'BSD-3-Clause' @@ -13,8 +13,7 @@ Pod::Spec.new do |s| s.source_files = 'src/google/protobuf/*.{h,cc,inc}', 'src/google/protobuf/stubs/*.{h,cc}', 'src/google/protobuf/io/*.{h,cc}', - 'src/google/protobuf/util/*.{h,cc}', - 'src/google/protobuf/util/internal/*.{h,cc}' + 'src/google/protobuf/util/*.{h,cc}' # Excluding all the tests in the directories above s.exclude_files = 'src/google/**/*_test.{h,cc,inc}', diff --git a/Protobuf.podspec b/Protobuf.podspec index 539bc9f8bf..d60e531b17 100644 --- a/Protobuf.podspec +++ b/Protobuf.podspec @@ -5,7 +5,7 @@ # dependent projects use the :git notation to refer to the library. Pod::Spec.new do |s| s.name = 'Protobuf' - s.version = '3.21.6' + s.version = '3.21.7' s.summary = 'Protocol Buffers v.3 runtime library for Objective-C.' s.homepage = 'https://github.com/protocolbuffers/protobuf' s.license = 'BSD-3-Clause' diff --git a/WORKSPACE b/WORKSPACE index 13c2bb0f13..82f523063a 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -16,6 +16,13 @@ http_archive( ], ) +http_archive( + name = "com_googlesource_code_re2", + sha256 = "906d0df8ff48f8d3a00a808827f009a840190f404559f649cb8e4d7143255ef9", + strip_prefix = "re2-a276a8c738735a0fe45a6ee590fe2df69bcf4502", + urls = ["https://github.com/google/re2/archive/a276a8c738735a0fe45a6ee590fe2df69bcf4502.zip"], # 2022-04-08 +) + # Bazel platform rules. http_archive( name = "platforms", @@ -48,6 +55,13 @@ pinned_maven_install() # For `cc_proto_blacklist_test` and `build_test`. load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") +load("@rules_python//python:pip.bzl", "pip_install") + +pip_install( + name="pip_deps", + requirements = "//python:requirements.txt" +) + bazel_skylib_workspace() load("@rules_pkg//:deps.bzl", "rules_pkg_dependencies") diff --git a/build_defs/cpp_opts.bzl b/build_defs/cpp_opts.bzl index 912c19b3c0..ab90a9d38e 100644 --- a/build_defs/cpp_opts.bzl +++ b/build_defs/cpp_opts.bzl @@ -21,7 +21,9 @@ COPTS = select({ "-Wno-sign-compare", "-Werror", ], -}) +}) + [ + "-std=c++14", # Protobuf requires C++14. +] # Android and MSVC builds do not need to link in a separate pthread library. LINK_OPTS = select({ diff --git a/conformance/binary_json_conformance_suite.cc b/conformance/binary_json_conformance_suite.cc index 689e8e1799..e6d33babae 100644 --- a/conformance/binary_json_conformance_suite.cc +++ b/conformance/binary_json_conformance_suite.cc @@ -37,6 +37,7 @@ #include "absl/status/status.h" #include "absl/strings/str_cat.h" #include "third_party/jsoncpp/json.h" +#include "conformance/conformance.pb.h" #include "conformance_test.h" #include "google/protobuf/test_messages_proto2.pb.h" #include "google/protobuf/test_messages_proto3.pb.h" @@ -60,6 +61,10 @@ namespace { static const char kTypeUrlPrefix[] = "type.googleapis.com"; +// The number of repetitions to use for performance tests. +// Corresponds approx to 500KB wireformat bytes. +static const size_t kPerformanceRepeatCount = 50000; + static string GetTypeUrl(const Descriptor* message) { return string(kTypeUrlPrefix) + "/" + message->full_name(); } @@ -477,6 +482,25 @@ void BinaryAndJsonConformanceSuite::RunValidJsonTest( const string& test_name, ConformanceLevel level, const string& input_json, const string& equivalent_text_format) { TestAllTypesProto3 prototype; + RunValidJsonTestWithMessage(test_name, level, input_json, + equivalent_text_format, prototype); +} + +void BinaryAndJsonConformanceSuite::RunValidJsonTest( + const string& test_name, ConformanceLevel level, const string& input_json, + const string& equivalent_text_format, bool is_proto3) { + if (is_proto3) { + RunValidJsonTest(test_name, level, input_json, equivalent_text_format); + } else { + TestAllTypesProto2 prototype; + RunValidJsonTestWithMessage(test_name, level, input_json, + equivalent_text_format, prototype); + } +} + +void BinaryAndJsonConformanceSuite::RunValidJsonTestWithMessage( + const string& test_name, ConformanceLevel level, const string& input_json, + const string& equivalent_text_format, const Message& prototype) { ConformanceRequestSetting setting1( level, conformance::JSON, conformance::PROTOBUF, conformance::JSON_TEST, @@ -550,6 +574,27 @@ void BinaryAndJsonConformanceSuite::RunValidBinaryProtobufTest( RunValidBinaryInputTest(setting, expected_protobuf, true); } +void BinaryAndJsonConformanceSuite::RunBinaryPerformanceMergeMessageWithField( + const string& test_name, const string& field_proto, bool is_proto3) { + string message_tag = tag(27, WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + string message_proto = cat(message_tag, delim(field_proto)); + + string proto; + for (size_t i = 0; i < kPerformanceRepeatCount; i++) { + proto.append(message_proto); + } + + string multiple_repeated_field_proto; + for (size_t i = 0; i < kPerformanceRepeatCount; i++) { + multiple_repeated_field_proto.append(field_proto); + } + string expected_proto = + cat(message_tag, delim(multiple_repeated_field_proto)); + + RunValidBinaryProtobufTest(test_name, RECOMMENDED, proto, expected_proto, + is_proto3); +} + void BinaryAndJsonConformanceSuite::RunValidProtobufTestWithMessage( const string& test_name, ConformanceLevel level, const Message *input, const string& equivalent_text_format, bool is_proto3) { @@ -1311,6 +1356,60 @@ void BinaryAndJsonConformanceSuite::TestUnknownMessage( message.SerializeAsString(), is_proto3); } +void BinaryAndJsonConformanceSuite:: + TestBinaryPerformanceForAlternatingUnknownFields() { + string unknown_field_1 = + cat(tag(UNKNOWN_FIELD, WireFormatLite::WIRETYPE_VARINT), varint(1234)); + string unknown_field_2 = cat( + tag(UNKNOWN_FIELD + 1, WireFormatLite::WIRETYPE_VARINT), varint(5678)); + for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { + string proto; + for (size_t i = 0; i < kPerformanceRepeatCount; i++) { + proto.append(unknown_field_1); + proto.append(unknown_field_2); + } + + RunValidBinaryProtobufTest( + "TestBinaryPerformanceForAlternatingUnknownFields", RECOMMENDED, proto, + is_proto3); + } +} + +void BinaryAndJsonConformanceSuite:: + TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( + FieldDescriptor::Type type) { + const string type_name = + UpperCase(string(".") + FieldDescriptor::TypeName(type)); + for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { + int field_number = + GetFieldForType(type, true, is_proto3, Packed::kFalse)->number(); + string rep_field_proto = cat( + tag(field_number, WireFormatLite::WireTypeForFieldType( + static_cast(type))), + GetNonDefaultValue(type)); + + RunBinaryPerformanceMergeMessageWithField( + "TestBinaryPerformanceMergeMessageWithRepeatedFieldForType" + type_name, + rep_field_proto, is_proto3); + } +} + +void BinaryAndJsonConformanceSuite:: + TestBinaryPerformanceMergeMessageWithUnknownFieldForType( + FieldDescriptor::Type type) { + const string type_name = + UpperCase(string(".") + FieldDescriptor::TypeName(type)); + string unknown_field_proto = + cat(tag(UNKNOWN_FIELD, WireFormatLite::WireTypeForFieldType( + static_cast(type))), + GetNonDefaultValue(type)); + for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { + RunBinaryPerformanceMergeMessageWithField( + "TestBinaryPerformanceMergeMessageWithUnknownFieldForType" + type_name, + unknown_field_proto, is_proto3); + } +} + void BinaryAndJsonConformanceSuite::RunSuiteImpl() { // Hack to get the list of test failures based on whether // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER is enabled or not. @@ -1330,232 +1429,324 @@ void BinaryAndJsonConformanceSuite::RunSuiteImpl() { kTypeUrlPrefix, DescriptorPool::generated_pool())); type_url_ = GetTypeUrl(TestAllTypesProto3::descriptor()); - for (int i = 1; i <= FieldDescriptor::MAX_TYPE; i++) { - if (i == FieldDescriptor::TYPE_GROUP) continue; - TestPrematureEOFForType(static_cast(i)); - } + if (!performance_) { + for (int i = 1; i <= FieldDescriptor::MAX_TYPE; i++) { + if (i == FieldDescriptor::TYPE_GROUP) continue; + TestPrematureEOFForType(static_cast(i)); + } - TestIllegalTags(); - - int64 kInt64Min = -9223372036854775808ULL; - int64 kInt64Max = 9223372036854775807ULL; - uint64 kUint64Max = 18446744073709551615ULL; - int32 kInt32Max = 2147483647; - int32 kInt32Min = -2147483648; - uint32 kUint32Max = 4294967295UL; - - TestValidDataForType( - FieldDescriptor::TYPE_DOUBLE, - { - {dbl(0), dbl(0)}, - {dbl(0.1), dbl(0.1)}, - {dbl(1.7976931348623157e+308), dbl(1.7976931348623157e+308)}, - {dbl(2.22507385850720138309e-308), dbl(2.22507385850720138309e-308)}, - }); - TestValidDataForType( - FieldDescriptor::TYPE_FLOAT, - { - {flt(0), flt(0)}, - {flt(0.1), flt(0.1)}, - {flt(1.00000075e-36), flt(1.00000075e-36)}, - {flt(3.402823e+38), flt(3.402823e+38)}, // 3.40282347e+38 - {flt(1.17549435e-38f), flt(1.17549435e-38)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_INT64, - { - {varint(0), varint(0)}, - {varint(12345), varint(12345)}, - {varint(kInt64Max), varint(kInt64Max)}, - {varint(kInt64Min), varint(kInt64Min)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_UINT64, - { - {varint(0), varint(0)}, - {varint(12345), varint(12345)}, - {varint(kUint64Max), varint(kUint64Max)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_INT32, - { - {varint(0), varint(0)}, - {varint(12345), varint(12345)}, - {longvarint(12345, 2), varint(12345)}, - {longvarint(12345, 7), varint(12345)}, - {varint(kInt32Max), varint(kInt32Max)}, - {varint(kInt32Min), varint(kInt32Min)}, - {varint(1LL << 33), varint(0)}, - {varint((1LL << 33) - 1), varint(-1)}, - {varint(kInt64Max), varint(-1)}, - {varint(kInt64Min + 1), varint(1)}, - }); - TestValidDataForType( - FieldDescriptor::TYPE_UINT32, - { - {varint(0), varint(0)}, - {varint(12345), varint(12345)}, - {longvarint(12345, 2), varint(12345)}, - {longvarint(12345, 7), varint(12345)}, - {varint(kUint32Max), varint(kUint32Max)}, // UINT32_MAX - {varint(1LL << 33), varint(0)}, - {varint((1LL << 33) + 1), varint(1)}, - {varint((1LL << 33) - 1), varint((1LL << 32) - 1)}, - {varint(kInt64Max), varint((1LL << 32) - 1)}, - {varint(kInt64Min + 1), varint(1)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_FIXED64, - { - {u64(0), u64(0)}, - {u64(12345), u64(12345)}, - {u64(kUint64Max), u64(kUint64Max)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_FIXED32, - { - {u32(0), u32(0)}, - {u32(12345), u32(12345)}, - {u32(kUint32Max), u32(kUint32Max)}, // UINT32_MAX - }); - TestValidDataForType(FieldDescriptor::TYPE_SFIXED64, - { - {u64(0), u64(0)}, - {u64(12345), u64(12345)}, - {u64(kInt64Max), u64(kInt64Max)}, - {u64(kInt64Min), u64(kInt64Min)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_SFIXED32, - { - {u32(0), u32(0)}, - {u32(12345), u32(12345)}, - {u32(kInt32Max), u32(kInt32Max)}, - {u32(kInt32Min), u32(kInt32Min)}, - }); - // Bools should be serialized as 0 for false and 1 for true. Parsers should - // also interpret any nonzero value as true. - TestValidDataForType(FieldDescriptor::TYPE_BOOL, - { - {varint(0), varint(0)}, - {varint(1), varint(1)}, - {varint(-1), varint(1)}, - {varint(12345678), varint(1)}, - {varint(1LL << 33), varint(1)}, - {varint(kInt64Max), varint(1)}, - {varint(kInt64Min), varint(1)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_SINT32, - { - {zz32(0), zz32(0)}, - {zz32(12345), zz32(12345)}, - {zz32(kInt32Max), zz32(kInt32Max)}, - {zz32(kInt32Min), zz32(kInt32Min)}, - {zz64(kInt32Max + 2LL), zz32(1)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_SINT64, - { - {zz64(0), zz64(0)}, - {zz64(12345), zz64(12345)}, - {zz64(kInt64Max), zz64(kInt64Max)}, - {zz64(kInt64Min), zz64(kInt64Min)}, - }); - TestValidDataForType( - FieldDescriptor::TYPE_STRING, - { - {delim(""), delim("")}, - {delim("Hello world!"), delim("Hello world!")}, - {delim("\'\"\?\\\a\b\f\n\r\t\v"), - delim("\'\"\?\\\a\b\f\n\r\t\v")}, // escape - {delim("谷歌"), delim("谷歌")}, // Google in Chinese - {delim("\u8C37\u6B4C"), delim("谷歌")}, // unicode escape - {delim("\u8c37\u6b4c"), delim("谷歌")}, // lowercase unicode - {delim("\xF0\x9F\x98\x81"), delim("\xF0\x9F\x98\x81")}, // emoji: 😁 - }); - TestValidDataForType(FieldDescriptor::TYPE_BYTES, - { - {delim(""), delim("")}, - {delim("Hello world!"), delim("Hello world!")}, - {delim("\x01\x02"), delim("\x01\x02")}, - {delim("\xfb"), delim("\xfb")}, - }); - TestValidDataForType(FieldDescriptor::TYPE_ENUM, - { - {varint(0), varint(0)}, - {varint(1), varint(1)}, - {varint(2), varint(2)}, - {varint(-1), varint(-1)}, - {varint(kInt64Max), varint(-1)}, - {varint(kInt64Min + 1), varint(1)}, - }); - TestValidDataForRepeatedScalarMessage(); - TestValidDataForType( - FieldDescriptor::TYPE_MESSAGE, - { - {delim(""), delim("")}, - {delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1234))), - delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1234)))}, - }); - - TestValidDataForMapType(FieldDescriptor::TYPE_INT32, - FieldDescriptor::TYPE_INT32); - TestValidDataForMapType(FieldDescriptor::TYPE_INT64, - FieldDescriptor::TYPE_INT64); - TestValidDataForMapType(FieldDescriptor::TYPE_UINT32, - FieldDescriptor::TYPE_UINT32); - TestValidDataForMapType(FieldDescriptor::TYPE_UINT64, - FieldDescriptor::TYPE_UINT64); - TestValidDataForMapType(FieldDescriptor::TYPE_SINT32, - FieldDescriptor::TYPE_SINT32); - TestValidDataForMapType(FieldDescriptor::TYPE_SINT64, - FieldDescriptor::TYPE_SINT64); - TestValidDataForMapType(FieldDescriptor::TYPE_FIXED32, - FieldDescriptor::TYPE_FIXED32); - TestValidDataForMapType(FieldDescriptor::TYPE_FIXED64, - FieldDescriptor::TYPE_FIXED64); - TestValidDataForMapType(FieldDescriptor::TYPE_SFIXED32, - FieldDescriptor::TYPE_SFIXED32); - TestValidDataForMapType(FieldDescriptor::TYPE_SFIXED64, - FieldDescriptor::TYPE_SFIXED64); - TestValidDataForMapType(FieldDescriptor::TYPE_INT32, - FieldDescriptor::TYPE_FLOAT); - TestValidDataForMapType(FieldDescriptor::TYPE_INT32, - FieldDescriptor::TYPE_DOUBLE); - TestValidDataForMapType(FieldDescriptor::TYPE_BOOL, - FieldDescriptor::TYPE_BOOL); - TestValidDataForMapType(FieldDescriptor::TYPE_STRING, - FieldDescriptor::TYPE_STRING); - TestValidDataForMapType(FieldDescriptor::TYPE_STRING, - FieldDescriptor::TYPE_BYTES); - TestValidDataForMapType(FieldDescriptor::TYPE_STRING, - FieldDescriptor::TYPE_ENUM); - TestValidDataForMapType(FieldDescriptor::TYPE_STRING, - FieldDescriptor::TYPE_MESSAGE); - // Additional test to check overwriting message value map. - TestOverwriteMessageValueMap(); - - TestValidDataForOneofType(FieldDescriptor::TYPE_UINT32); - TestValidDataForOneofType(FieldDescriptor::TYPE_BOOL); - TestValidDataForOneofType(FieldDescriptor::TYPE_UINT64); - TestValidDataForOneofType(FieldDescriptor::TYPE_FLOAT); - TestValidDataForOneofType(FieldDescriptor::TYPE_DOUBLE); - TestValidDataForOneofType(FieldDescriptor::TYPE_STRING); - TestValidDataForOneofType(FieldDescriptor::TYPE_BYTES); - TestValidDataForOneofType(FieldDescriptor::TYPE_ENUM); - TestValidDataForOneofType(FieldDescriptor::TYPE_MESSAGE); - // Additional test to check merging oneof message. - TestMergeOneofMessage(); - - // TODO(haberman): - // TestValidDataForType(FieldDescriptor::TYPE_GROUP - - // Unknown fields. - { - TestAllTypesProto3 messageProto3; - TestAllTypesProto2 messageProto2; - // TODO(yilunchong): update this behavior when unknown field's behavior - // changed in open source. Also delete - // Required.Proto3.ProtobufInput.UnknownVarint.ProtobufOutput - // from failure list of python_cpp python java - TestUnknownMessage(messageProto3, true); - TestUnknownMessage(messageProto2, false); + TestIllegalTags(); + + int64 kInt64Min = -9223372036854775808ULL; + int64 kInt64Max = 9223372036854775807ULL; + uint64 kUint64Max = 18446744073709551615ULL; + int32 kInt32Max = 2147483647; + int32 kInt32Min = -2147483648; + uint32 kUint32Max = 4294967295UL; + + TestValidDataForType( + FieldDescriptor::TYPE_DOUBLE, + { + {dbl(0), dbl(0)}, + {dbl(0.1), dbl(0.1)}, + {dbl(1.7976931348623157e+308), dbl(1.7976931348623157e+308)}, + {dbl(2.22507385850720138309e-308), + dbl(2.22507385850720138309e-308)}, + }); + TestValidDataForType( + FieldDescriptor::TYPE_FLOAT, + { + {flt(0), flt(0)}, + {flt(0.1), flt(0.1)}, + {flt(1.00000075e-36), flt(1.00000075e-36)}, + {flt(3.402823e+38), flt(3.402823e+38)}, // 3.40282347e+38 + {flt(1.17549435e-38f), flt(1.17549435e-38)}, + }); + TestValidDataForType(FieldDescriptor::TYPE_INT64, + { + {varint(0), varint(0)}, + {varint(12345), varint(12345)}, + {varint(kInt64Max), varint(kInt64Max)}, + {varint(kInt64Min), varint(kInt64Min)}, + }); + TestValidDataForType(FieldDescriptor::TYPE_UINT64, + { + {varint(0), varint(0)}, + {varint(12345), varint(12345)}, + {varint(kUint64Max), varint(kUint64Max)}, + }); + TestValidDataForType(FieldDescriptor::TYPE_INT32, + { + {varint(0), varint(0)}, + {varint(12345), varint(12345)}, + {longvarint(12345, 2), varint(12345)}, + {longvarint(12345, 7), varint(12345)}, + {varint(kInt32Max), varint(kInt32Max)}, + {varint(kInt32Min), varint(kInt32Min)}, + {varint(1LL << 33), varint(0)}, + {varint((1LL << 33) - 1), varint(-1)}, + {varint(kInt64Max), varint(-1)}, + {varint(kInt64Min + 1), varint(1)}, + }); + TestValidDataForType( + FieldDescriptor::TYPE_UINT32, + { + {varint(0), varint(0)}, + {varint(12345), varint(12345)}, + {longvarint(12345, 2), varint(12345)}, + {longvarint(12345, 7), varint(12345)}, + {varint(kUint32Max), varint(kUint32Max)}, // UINT32_MAX + {varint(1LL << 33), varint(0)}, + {varint((1LL << 33) + 1), varint(1)}, + {varint((1LL << 33) - 1), varint((1LL << 32) - 1)}, + {varint(kInt64Max), varint((1LL << 32) - 1)}, + {varint(kInt64Min + 1), varint(1)}, + }); + TestValidDataForType(FieldDescriptor::TYPE_FIXED64, + { + {u64(0), u64(0)}, + {u64(12345), u64(12345)}, + {u64(kUint64Max), u64(kUint64Max)}, + }); + TestValidDataForType(FieldDescriptor::TYPE_FIXED32, + { + {u32(0), u32(0)}, + {u32(12345), u32(12345)}, + {u32(kUint32Max), u32(kUint32Max)}, // UINT32_MAX + }); + TestValidDataForType(FieldDescriptor::TYPE_SFIXED64, + { + {u64(0), u64(0)}, + {u64(12345), u64(12345)}, + {u64(kInt64Max), u64(kInt64Max)}, + {u64(kInt64Min), u64(kInt64Min)}, + }); + TestValidDataForType(FieldDescriptor::TYPE_SFIXED32, + { + {u32(0), u32(0)}, + {u32(12345), u32(12345)}, + {u32(kInt32Max), u32(kInt32Max)}, + {u32(kInt32Min), u32(kInt32Min)}, + }); + // Bools should be serialized as 0 for false and 1 for true. Parsers should + // also interpret any nonzero value as true. + TestValidDataForType(FieldDescriptor::TYPE_BOOL, + { + {varint(0), varint(0)}, + {varint(1), varint(1)}, + {varint(-1), varint(1)}, + {varint(12345678), varint(1)}, + {varint(1LL << 33), varint(1)}, + {varint(kInt64Max), varint(1)}, + {varint(kInt64Min), varint(1)}, + }); + TestValidDataForType(FieldDescriptor::TYPE_SINT32, + { + {zz32(0), zz32(0)}, + {zz32(12345), zz32(12345)}, + {zz32(kInt32Max), zz32(kInt32Max)}, + {zz32(kInt32Min), zz32(kInt32Min)}, + {zz64(kInt32Max + 2LL), zz32(1)}, + }); + TestValidDataForType(FieldDescriptor::TYPE_SINT64, + { + {zz64(0), zz64(0)}, + {zz64(12345), zz64(12345)}, + {zz64(kInt64Max), zz64(kInt64Max)}, + {zz64(kInt64Min), zz64(kInt64Min)}, + }); + TestValidDataForType( + FieldDescriptor::TYPE_STRING, + { + {delim(""), delim("")}, + {delim("Hello world!"), delim("Hello world!")}, + {delim("\'\"\?\\\a\b\f\n\r\t\v"), + delim("\'\"\?\\\a\b\f\n\r\t\v")}, // escape + {delim("谷歌"), delim("谷歌")}, // Google in Chinese + {delim("\u8C37\u6B4C"), delim("谷歌")}, // unicode escape + {delim("\u8c37\u6b4c"), delim("谷歌")}, // lowercase unicode + {delim("\xF0\x9F\x98\x81"), delim("\xF0\x9F\x98\x81")}, // emoji: 😁 + }); + TestValidDataForType(FieldDescriptor::TYPE_BYTES, + { + {delim(""), delim("")}, + {delim("Hello world!"), delim("Hello world!")}, + {delim("\x01\x02"), delim("\x01\x02")}, + {delim("\xfb"), delim("\xfb")}, + }); + TestValidDataForType(FieldDescriptor::TYPE_ENUM, + { + {varint(0), varint(0)}, + {varint(1), varint(1)}, + {varint(2), varint(2)}, + {varint(-1), varint(-1)}, + {varint(kInt64Max), varint(-1)}, + {varint(kInt64Min + 1), varint(1)}, + }); + TestValidDataForRepeatedScalarMessage(); + TestValidDataForType( + FieldDescriptor::TYPE_MESSAGE, + { + {delim(""), delim("")}, + {delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1234))), + delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1234)))}, + }); + + TestValidDataForMapType(FieldDescriptor::TYPE_INT32, + FieldDescriptor::TYPE_INT32); + TestValidDataForMapType(FieldDescriptor::TYPE_INT64, + FieldDescriptor::TYPE_INT64); + TestValidDataForMapType(FieldDescriptor::TYPE_UINT32, + FieldDescriptor::TYPE_UINT32); + TestValidDataForMapType(FieldDescriptor::TYPE_UINT64, + FieldDescriptor::TYPE_UINT64); + TestValidDataForMapType(FieldDescriptor::TYPE_SINT32, + FieldDescriptor::TYPE_SINT32); + TestValidDataForMapType(FieldDescriptor::TYPE_SINT64, + FieldDescriptor::TYPE_SINT64); + TestValidDataForMapType(FieldDescriptor::TYPE_FIXED32, + FieldDescriptor::TYPE_FIXED32); + TestValidDataForMapType(FieldDescriptor::TYPE_FIXED64, + FieldDescriptor::TYPE_FIXED64); + TestValidDataForMapType(FieldDescriptor::TYPE_SFIXED32, + FieldDescriptor::TYPE_SFIXED32); + TestValidDataForMapType(FieldDescriptor::TYPE_SFIXED64, + FieldDescriptor::TYPE_SFIXED64); + TestValidDataForMapType(FieldDescriptor::TYPE_INT32, + FieldDescriptor::TYPE_FLOAT); + TestValidDataForMapType(FieldDescriptor::TYPE_INT32, + FieldDescriptor::TYPE_DOUBLE); + TestValidDataForMapType(FieldDescriptor::TYPE_BOOL, + FieldDescriptor::TYPE_BOOL); + TestValidDataForMapType(FieldDescriptor::TYPE_STRING, + FieldDescriptor::TYPE_STRING); + TestValidDataForMapType(FieldDescriptor::TYPE_STRING, + FieldDescriptor::TYPE_BYTES); + TestValidDataForMapType(FieldDescriptor::TYPE_STRING, + FieldDescriptor::TYPE_ENUM); + TestValidDataForMapType(FieldDescriptor::TYPE_STRING, + FieldDescriptor::TYPE_MESSAGE); + // Additional test to check overwriting message value map. + TestOverwriteMessageValueMap(); + + TestValidDataForOneofType(FieldDescriptor::TYPE_UINT32); + TestValidDataForOneofType(FieldDescriptor::TYPE_BOOL); + TestValidDataForOneofType(FieldDescriptor::TYPE_UINT64); + TestValidDataForOneofType(FieldDescriptor::TYPE_FLOAT); + TestValidDataForOneofType(FieldDescriptor::TYPE_DOUBLE); + TestValidDataForOneofType(FieldDescriptor::TYPE_STRING); + TestValidDataForOneofType(FieldDescriptor::TYPE_BYTES); + TestValidDataForOneofType(FieldDescriptor::TYPE_ENUM); + TestValidDataForOneofType(FieldDescriptor::TYPE_MESSAGE); + // Additional test to check merging oneof message. + TestMergeOneofMessage(); + + // TODO(haberman): + // TestValidDataForType(FieldDescriptor::TYPE_GROUP + + // Unknown fields. + { + TestAllTypesProto3 messageProto3; + TestAllTypesProto2 messageProto2; + // TODO(yilunchong): update this behavior when unknown field's behavior + // changed in open source. Also delete + // Required.Proto3.ProtobufInput.UnknownVarint.ProtobufOutput + // from failure list of python_cpp python java + TestUnknownMessage(messageProto3, true); + TestUnknownMessage(messageProto2, false); + } + + RunJsonTests(); } + // Flag control performance tests to keep them internal and opt-in only + if (performance_) { + RunBinaryPerformanceTests(); + RunJsonPerformanceTests(); + } +} + +void BinaryAndJsonConformanceSuite::RunBinaryPerformanceTests() { + TestBinaryPerformanceForAlternatingUnknownFields(); + + TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( + FieldDescriptor::TYPE_BOOL); + TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( + FieldDescriptor::TYPE_DOUBLE); + TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( + FieldDescriptor::TYPE_FLOAT); + TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( + FieldDescriptor::TYPE_UINT32); + TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( + FieldDescriptor::TYPE_UINT64); + TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( + FieldDescriptor::TYPE_STRING); + TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( + FieldDescriptor::TYPE_BYTES); + + TestBinaryPerformanceMergeMessageWithUnknownFieldForType( + FieldDescriptor::TYPE_BOOL); + TestBinaryPerformanceMergeMessageWithUnknownFieldForType( + FieldDescriptor::TYPE_DOUBLE); + TestBinaryPerformanceMergeMessageWithUnknownFieldForType( + FieldDescriptor::TYPE_FLOAT); + TestBinaryPerformanceMergeMessageWithUnknownFieldForType( + FieldDescriptor::TYPE_UINT32); + TestBinaryPerformanceMergeMessageWithUnknownFieldForType( + FieldDescriptor::TYPE_UINT64); + TestBinaryPerformanceMergeMessageWithUnknownFieldForType( + FieldDescriptor::TYPE_STRING); + TestBinaryPerformanceMergeMessageWithUnknownFieldForType( + FieldDescriptor::TYPE_BYTES); +} + +void BinaryAndJsonConformanceSuite::RunJsonPerformanceTests() { + TestJsonPerformanceMergeMessageWithRepeatedFieldForType( + FieldDescriptor::TYPE_BOOL, "true"); + TestJsonPerformanceMergeMessageWithRepeatedFieldForType( + FieldDescriptor::TYPE_DOUBLE, "123"); + TestJsonPerformanceMergeMessageWithRepeatedFieldForType( + FieldDescriptor::TYPE_FLOAT, "123"); + TestJsonPerformanceMergeMessageWithRepeatedFieldForType( + FieldDescriptor::TYPE_UINT32, "123"); + TestJsonPerformanceMergeMessageWithRepeatedFieldForType( + FieldDescriptor::TYPE_UINT64, "123"); + TestJsonPerformanceMergeMessageWithRepeatedFieldForType( + FieldDescriptor::TYPE_STRING, "\"foo\""); + TestJsonPerformanceMergeMessageWithRepeatedFieldForType( + FieldDescriptor::TYPE_BYTES, "\"foo\""); +} + +// This is currently considered valid input by some languages but not others +void BinaryAndJsonConformanceSuite:: + TestJsonPerformanceMergeMessageWithRepeatedFieldForType( + FieldDescriptor::Type type, string field_value) { + const string type_name = + UpperCase(string(".") + FieldDescriptor::TypeName(type)); + for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { + const FieldDescriptor* field = + GetFieldForType(type, true, is_proto3, Packed::kFalse); + string field_name = field->name(); + + string message_field = "\"" + field_name + "\": [" + field_value + "]"; + string recursive_message = + "\"recursive_message\": { " + message_field + "}"; + string input = "{"; + input.append(recursive_message); + for (size_t i = 1; i < kPerformanceRepeatCount; i++) { + input.append("," + recursive_message); + } + input.append("}"); - RunJsonTests(); + string textproto_message_field = field_name + ": " + field_value; + string expected_textproto = "recursive_message { "; + for (size_t i = 0; i < kPerformanceRepeatCount; i++) { + expected_textproto.append(textproto_message_field + " "); + } + expected_textproto.append("}"); + RunValidJsonTest( + "TestJsonPerformanceMergeMessageWithRepeatedFieldForType" + type_name, + RECOMMENDED, input, expected_textproto, is_proto3); + } } void BinaryAndJsonConformanceSuite::RunJsonTests() { diff --git a/conformance/binary_json_conformance_suite.h b/conformance/binary_json_conformance_suite.h index 280ff95bbb..cdfbc431de 100644 --- a/conformance/binary_json_conformance_suite.h +++ b/conformance/binary_json_conformance_suite.h @@ -31,6 +31,7 @@ #ifndef CONFORMANCE_BINARY_JSON_CONFORMANCE_SUITE_H #define CONFORMANCE_BINARY_JSON_CONFORMANCE_SUITE_H +#include "google/protobuf/descriptor.h" #include "third_party/jsoncpp/json.h" #include "conformance_test.h" @@ -43,6 +44,8 @@ class BinaryAndJsonConformanceSuite : public ConformanceTestSuite { private: void RunSuiteImpl() override; + void RunBinaryPerformanceTests(); + void RunJsonPerformanceTests(); void RunJsonTests(); void RunJsonTestsForFieldNameConvention(); void RunJsonTestsForNonRepeatedTypes(); @@ -56,6 +59,15 @@ class BinaryAndJsonConformanceSuite : public ConformanceTestSuite { void RunValidJsonTest(const std::string& test_name, ConformanceLevel level, const std::string& input_json, const std::string& equivalent_text_format); + void RunValidJsonTest(const std::string& test_name, ConformanceLevel level, + const std::string& input_json, + const std::string& equivalent_text_format, + bool is_proto3); + void RunValidJsonTestWithMessage(const std::string& test_name, + ConformanceLevel level, + const std::string& input_json, + const std::string& equivalent_text_forma, + const Message& prototype); void RunValidJsonTestWithProtobufInput( const std::string& test_name, ConformanceLevel level, const protobuf_test_messages::proto3::TestAllTypesProto3& input, @@ -78,6 +90,10 @@ class BinaryAndJsonConformanceSuite : public ConformanceTestSuite { const std::string& input_protobuf, const std::string& expected_protobuf, bool is_proto3); + void RunBinaryPerformanceMergeMessageWithField(const std::string& test_name, + const std::string& field_proto, + bool is_proto3); + void RunValidProtobufTestWithMessage( const std::string& test_name, ConformanceLevel level, const Message* input, const std::string& equivalent_text_format, @@ -130,6 +146,13 @@ class BinaryAndJsonConformanceSuite : public ConformanceTestSuite { void TestValidDataForOneofType(google::protobuf::FieldDescriptor::Type); void TestMergeOneofMessage(); void TestOverwriteMessageValueMap(); + void TestBinaryPerformanceForAlternatingUnknownFields(); + void TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( + google::protobuf::FieldDescriptor::Type); + void TestBinaryPerformanceMergeMessageWithUnknownFieldForType( + google::protobuf::FieldDescriptor::Type); + void TestJsonPerformanceMergeMessageWithRepeatedFieldForType( + google::protobuf::FieldDescriptor::Type, std::string field_value); std::unique_ptr type_resolver_; std::string type_url_; diff --git a/conformance/conformance.proto b/conformance/conformance.proto index a9edbab823..a213437f89 100644 --- a/conformance/conformance.proto +++ b/conformance/conformance.proto @@ -29,8 +29,11 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. syntax = "proto3"; + package conformance; + option java_package = "com.google.protobuf.conformance"; +option objc_class_prefix = "Conformance"; // This defines the conformance testing protocol. This protocol exists between // the conformance test suite itself and the code being tested. For each test, @@ -69,7 +72,8 @@ enum TestCategory { // https://developers.google.com/protocol-buffers/docs/proto3#json_options // for more detail. JSON_IGNORE_UNKNOWN_PARSING_TEST = 3; - // Test jspb wire format. Google internal only. Opensource testees just skip it. + // Test jspb wire format. Google internal only. Opensource testees just skip + // it. JSPB_TEST = 4; // Test text format. For cpp, java and python, testees can already deal with // this type. Testees of other languages can simply skip it. @@ -109,8 +113,8 @@ message ConformanceRequest { string message_type = 4; // Each test is given a specific test category. Some category may need - // specific support in testee programs. Refer to the definition of TestCategory - // for more information. + // specific support in testee programs. Refer to the definition of + // TestCategory for more information. TestCategory test_category = 5; // Specify details for how to encode jspb. @@ -136,6 +140,11 @@ message ConformanceResponse { // this field. string serialize_error = 6; + // This should be set if the test program timed out. The string should + // provide more information about what the child process was doing when it + // was killed. + string timeout_error = 9; + // This should be set if some other error occurred. This will always // indicate that the test failed. The string can provide more information // about the failure. @@ -169,4 +178,3 @@ message JspbEncodingConfig { // Encode the value field of Any as jspb array if true, otherwise binary. bool use_jspb_array_any_format = 1; } - diff --git a/conformance/conformance_objc.m b/conformance/conformance_objc.m index ab751c81de..909768ba5c 100644 --- a/conformance/conformance_objc.m +++ b/conformance/conformance_objc.m @@ -77,7 +77,7 @@ static ConformanceResponse *DoTest(ConformanceRequest *request) { if ([request.messageType isEqual:@"protobuf_test_messages.proto3.TestAllTypesProto3"]) { msgClass = [Proto3TestAllTypesProto3 class]; } else if ([request.messageType isEqual:@"protobuf_test_messages.proto2.TestAllTypesProto2"]) { - msgClass = [TestAllTypesProto2 class]; + msgClass = [Proto2TestAllTypesProto2 class]; } else { response.runtimeError = [NSString stringWithFormat:@"Protobuf request had an unknown message_type: %@", @@ -110,13 +110,13 @@ static ConformanceResponse *DoTest(ConformanceRequest *request) { if (testMessage) { switch (request.requestedOutputFormat) { - case WireFormat_GPBUnrecognizedEnumeratorValue: - case WireFormat_Unspecified: + case ConformanceWireFormat_GPBUnrecognizedEnumeratorValue: + case ConformanceWireFormat_Unspecified: response.runtimeError = [NSString stringWithFormat:@"Unrecognized/unspecified output format: %@", request]; break; - case WireFormat_Protobuf: + case ConformanceWireFormat_Protobuf: response.protobufPayload = testMessage.data; if (!response.protobufPayload) { response.serializeError = @@ -124,17 +124,17 @@ static ConformanceResponse *DoTest(ConformanceRequest *request) { } break; - case WireFormat_Json: + case ConformanceWireFormat_Json: response.skipped = @"ObjC doesn't support generating JSON"; break; - case WireFormat_Jspb: + case ConformanceWireFormat_Jspb: response.skipped = @"ConformanceRequest had a requested_output_format of JSPB WireFormat; that" " isn't supposed to happen with opensource."; break; - case WireFormat_TextFormat: + case ConformanceWireFormat_TextFormat: // ObjC only has partial objc generation, so don't attempt any tests that need // support. response.skipped = @"ObjC doesn't support generating TextFormat"; diff --git a/conformance/conformance_test.cc b/conformance/conformance_test.cc index e2a92969bd..00b309a336 100644 --- a/conformance/conformance_test.cc +++ b/conformance/conformance_test.cc @@ -44,6 +44,7 @@ #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "conformance/conformance.pb.h" +#include "conformance/conformance.pb.h" using conformance::ConformanceRequest; using conformance::ConformanceResponse; @@ -176,6 +177,59 @@ string ConformanceTestSuite::ConformanceRequestSetting:: return ""; } +void ConformanceTestSuite::TruncateDebugPayload(string* payload) { + if (payload != nullptr && payload->size() > 200) { + payload->resize(200); + payload->append("...(truncated)"); + } +} + +const ConformanceRequest ConformanceTestSuite::TruncateRequest( + const ConformanceRequest& request) { + ConformanceRequest debug_request(request); + switch (debug_request.payload_case()) { + case ConformanceRequest::kProtobufPayload: + TruncateDebugPayload(debug_request.mutable_protobuf_payload()); + break; + case ConformanceRequest::kJsonPayload: + TruncateDebugPayload(debug_request.mutable_json_payload()); + break; + case ConformanceRequest::kTextPayload: + TruncateDebugPayload(debug_request.mutable_text_payload()); + break; + case ConformanceRequest::kJspbPayload: + TruncateDebugPayload(debug_request.mutable_jspb_payload()); + break; + default: + // Do nothing. + break; + } + return debug_request; +} + +const ConformanceResponse ConformanceTestSuite::TruncateResponse( + const ConformanceResponse& response) { + ConformanceResponse debug_response(response); + switch (debug_response.result_case()) { + case ConformanceResponse::kProtobufPayload: + TruncateDebugPayload(debug_response.mutable_protobuf_payload()); + break; + case ConformanceResponse::kJsonPayload: + TruncateDebugPayload(debug_response.mutable_json_payload()); + break; + case ConformanceResponse::kTextPayload: + TruncateDebugPayload(debug_response.mutable_text_payload()); + break; + case ConformanceResponse::kJspbPayload: + TruncateDebugPayload(debug_response.mutable_jspb_payload()); + break; + default: + // Do nothing. + break; + } + return debug_response; +} + void ConformanceTestSuite::ReportSuccess(const string& test_name) { if (expected_to_fail_.erase(test_name) != 0) { absl::StrAppendFormat( @@ -203,9 +257,10 @@ void ConformanceTestSuite::ReportFailure(const string& test_name, absl::StrAppendFormat(&output_, "ERROR, test=%s: ", test_name); unexpected_failing_tests_.insert(test_name); } - absl::StrAppendFormat(&output_, "%s request=%s, response=%s\n", message, - request.ShortDebugString(), - response.ShortDebugString()); + + absl::StrAppendFormat(&output_, "%s, request=%s, response=%s\n", message, + TruncateRequest(request).ShortDebugString(), + TruncateResponse(response).ShortDebugString()); } void ConformanceTestSuite::ReportSkip(const string& test_name, @@ -261,6 +316,7 @@ void ConformanceTestSuite::VerifyResponse( return; case ConformanceResponse::kParseError: + case ConformanceResponse::kTimeoutError: case ConformanceResponse::kRuntimeError: case ConformanceResponse::kSerializeError: ReportFailure(test_name, level, request, response, @@ -327,7 +383,8 @@ void ConformanceTestSuite::RunTest(const string& test_name, if (verbose_) { absl::StrAppendFormat( &output_, "conformance test: name=%s, request=%s, response=%s\n", - test_name, request.ShortDebugString(), response->ShortDebugString()); + test_name, TruncateRequest(request).ShortDebugString(), + TruncateResponse(*response).ShortDebugString()); } } diff --git a/conformance/conformance_test.h b/conformance/conformance_test.h index f03b6d7038..527f0548cd 100644 --- a/conformance/conformance_test.h +++ b/conformance/conformance_test.h @@ -88,10 +88,12 @@ class ForkPipeRunner : public ConformanceTestRunner { const std::vector& suites); ForkPipeRunner(const std::string& executable, - const std::vector& executable_args) + const std::vector& executable_args, + bool performance) : child_pid_(-1), executable_(executable), - executable_args_(executable_args) {} + executable_args_(executable_args), + performance_(performance) {} explicit ForkPipeRunner(const std::string& executable) : child_pid_(-1), executable_(executable) {} @@ -114,6 +116,7 @@ class ForkPipeRunner : public ConformanceTestRunner { pid_t child_pid_; std::string executable_; const std::vector executable_args_; + bool performance_; std::string current_test_name_; }; @@ -148,10 +151,12 @@ class ConformanceTestSuite { public: ConformanceTestSuite() : verbose_(false), + performance_(false), enforce_recommended_(false), failure_list_flag_name_("--failure_list") {} virtual ~ConformanceTestSuite() {} + void SetPerformance(bool performance) { performance_ = performance; } void SetVerbose(bool verbose) { verbose_ = verbose; } // Whether to require the testee to pass RECOMMENDED tests. By default failing @@ -272,6 +277,12 @@ class ConformanceTestSuite { const conformance::ConformanceResponse& response, bool need_report_success, bool require_same_wire_format); + void TruncateDebugPayload(std::string* payload); + const conformance::ConformanceRequest TruncateRequest( + const conformance::ConformanceRequest& request); + const conformance::ConformanceResponse TruncateResponse( + const conformance::ConformanceResponse& response); + void ReportSuccess(const std::string& test_name); void ReportFailure(const std::string& test_name, ConformanceLevel level, const conformance::ConformanceRequest& request, @@ -299,6 +310,7 @@ class ConformanceTestSuite { int successes_; int expected_failures_; bool verbose_; + bool performance_; bool enforce_recommended_; std::string output_; std::string output_dir_; diff --git a/conformance/conformance_test_runner.cc b/conformance/conformance_test_runner.cc index 71224784ff..a60bdee189 100644 --- a/conformance/conformance_test_runner.cc +++ b/conformance/conformance_test_runner.cc @@ -54,12 +54,15 @@ // 4. testee sends M bytes representing a ConformanceResponse proto #include +#include #include #include #include #include +#include #include +#include #include #include "absl/strings/str_format.h" @@ -149,7 +152,6 @@ void ForkPipeRunner::RunTest(const std::string &test_name, if (child_pid_ < 0) { SpawnTestProgram(); } - current_test_name_ = test_name; uint32_t len = request.size(); @@ -164,9 +166,18 @@ void ForkPipeRunner::RunTest(const std::string &test_name, waitpid(child_pid_, &status, WEXITED); string error_msg; + conformance::ConformanceResponse response_obj; if (WIFEXITED(status)) { - absl::StrAppendFormat(&error_msg, "child exited, status=%d", - WEXITSTATUS(status)); + if (WEXITSTATUS(status) == 0) { + absl::StrAppendFormat(&error_msg, + "child timed out, killed by signal %d", + WTERMSIG(status)); + response_obj.set_timeout_error(error_msg); + } else { + absl::StrAppendFormat(&error_msg, "child exited, status=%d", + WEXITSTATUS(status)); + response_obj.set_runtime_error(error_msg); + } } else if (WIFSIGNALED(status)) { absl::StrAppendFormat(&error_msg, "child killed by signal %d", WTERMSIG(status)); @@ -174,8 +185,6 @@ void ForkPipeRunner::RunTest(const std::string &test_name, GOOGLE_LOG(INFO) << error_msg; child_pid_ = -1; - conformance::ConformanceResponse response_obj; - response_obj.set_runtime_error(error_msg); response_obj.SerializeToString(response); return; } @@ -197,11 +206,15 @@ int ForkPipeRunner::Run(int argc, char *argv[], string failure_list_filename; conformance::FailureSet failure_list; + bool performance = false; for (int arg = 1; arg < argc; ++arg) { if (strcmp(argv[arg], suite->GetFailureListFlagName().c_str()) == 0) { if (++arg == argc) UsageError(); failure_list_filename = argv[arg]; ParseFailureList(argv[arg], &failure_list); + } else if (strcmp(argv[arg], "--performance") == 0) { + performance = true; + suite->SetPerformance(true); } else if (strcmp(argv[arg], "--verbose") == 0) { suite->SetVerbose(true); } else if (strcmp(argv[arg], "--enforce_recommended") == 0) { @@ -230,7 +243,7 @@ int ForkPipeRunner::Run(int argc, char *argv[], } } - ForkPipeRunner runner(program, program_args); + ForkPipeRunner runner(program, program_args, performance); std::string output; all_ok = all_ok && suite->RunSuite(&runner, &output, failure_list_filename, @@ -319,8 +332,36 @@ void ForkPipeRunner::CheckedWrite(int fd, const void *buf, size_t len) { bool ForkPipeRunner::TryRead(int fd, void *buf, size_t len) { size_t ofs = 0; while (len > 0) { - ssize_t bytes_read = read(fd, (char *)buf + ofs, len); - + std::future future = std::async( + std::launch::async, + [](int fd, void *buf, size_t ofs, size_t len) { + return read(fd, (char *)buf + ofs, len); + }, + fd, buf, ofs, len); + std::future_status status; + if (performance_) { + status = future.wait_for(std::chrono::seconds(5)); + if (status == std::future_status::timeout) { + GOOGLE_LOG(ERROR) << current_test_name_ << ": timeout from test program"; + kill(child_pid_, SIGQUIT); + // TODO(sandyzhang): Only log in flag-guarded mode, since reading output + // from SIGQUIT is slow and verbose. + std::vector err; + err.resize(5000); + ssize_t err_bytes_read; + size_t err_ofs = 0; + do { + err_bytes_read = + read(fd, (void *)&err[err_ofs], err.size() - err_ofs); + err_ofs += err_bytes_read; + } while (err_bytes_read > 0 && err_ofs < err.size()); + GOOGLE_LOG(ERROR) << "child_pid_=" << child_pid_ << " SIGQUIT: \n" << &err[0]; + return false; + } + } else { + future.wait(); + } + ssize_t bytes_read = future.get(); if (bytes_read == 0) { GOOGLE_LOG(ERROR) << current_test_name_ << ": unexpected EOF from test program"; return false; diff --git a/conformance/failure_list_php_c.txt b/conformance/failure_list_php_c.txt index 52ca4544b6..63c7e8a024 100644 --- a/conformance/failure_list_php_c.txt +++ b/conformance/failure_list_php_c.txt @@ -1,5 +1,2 @@ Recommended.Proto2.JsonInput.FieldNameExtension.Validator Required.Proto2.JsonInput.StoresDefaultPrimitive.Validator -Required.Proto3.JsonInput.DurationNegativeNanos.JsonOutput -Required.Proto3.JsonInput.DurationNegativeNanos.ProtobufOutput -Required.Proto3.JsonInput.DurationNegativeSeconds.JsonOutput diff --git a/conformance/failure_list_ruby.txt b/conformance/failure_list_ruby.txt index ff230a26a9..4938202ad7 100644 --- a/conformance/failure_list_ruby.txt +++ b/conformance/failure_list_ruby.txt @@ -56,6 +56,3 @@ Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.PackedInput.UnpackedOu Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.UnpackedInput.UnpackedOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.UnpackedOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.UnpackedOutput.ProtobufOutput -Required.Proto3.JsonInput.DurationNegativeNanos.JsonOutput -Required.Proto3.JsonInput.DurationNegativeNanos.ProtobufOutput -Required.Proto3.JsonInput.DurationNegativeSeconds.JsonOutput diff --git a/conformance/text_format_conformance_suite.cc b/conformance/text_format_conformance_suite.cc index 958ed7b499..81dde5f687 100644 --- a/conformance/text_format_conformance_suite.cc +++ b/conformance/text_format_conformance_suite.cc @@ -51,6 +51,10 @@ using std::string; namespace google { namespace protobuf { +// The number of repetitions to use for performance tests. +// Corresponds approx to 500KB wireformat bytes. +static const size_t kPerformanceRepeatCount = 50000; + TextFormatConformanceTestSuite::TextFormatConformanceTestSuite() { SetFailureListFlagName("--text_format_failure_list"); } @@ -166,6 +170,22 @@ void TextFormatConformanceTestSuite::RunValidTextFormatTestProto2( RunValidTextFormatTestWithMessage(test_name, level, input_text, prototype); } +void TextFormatConformanceTestSuite::RunValidTextFormatTestWithExpected( + const string& test_name, ConformanceLevel level, const string& input_text, + const string& expected_text) { + TestAllTypesProto3 prototype; + RunValidTextFormatTestWithMessage(test_name, level, input_text, expected_text, + prototype); +} + +void TextFormatConformanceTestSuite::RunValidTextFormatTestProto2WithExpected( + const string& test_name, ConformanceLevel level, const string& input_text, + const string& expected_text) { + TestAllTypesProto2 prototype; + RunValidTextFormatTestWithMessage(test_name, level, input_text, expected_text, + prototype); +} + void TextFormatConformanceTestSuite::RunValidTextFormatTestWithMessage( const string& test_name, ConformanceLevel level, const string& input_text, const Message& prototype) { @@ -179,6 +199,19 @@ void TextFormatConformanceTestSuite::RunValidTextFormatTestWithMessage( RunValidInputTest(setting2, input_text); } +void TextFormatConformanceTestSuite::RunValidTextFormatTestWithMessage( + const string& test_name, ConformanceLevel level, const string& input_text, + const string& expected_text, const Message& prototype) { + ConformanceRequestSetting setting1( + level, conformance::TEXT_FORMAT, conformance::PROTOBUF, + conformance::TEXT_FORMAT_TEST, prototype, test_name, input_text); + RunValidInputTest(setting1, expected_text); + ConformanceRequestSetting setting2( + level, conformance::TEXT_FORMAT, conformance::TEXT_FORMAT, + conformance::TEXT_FORMAT_TEST, prototype, test_name, input_text); + RunValidInputTest(setting2, expected_text); +} + void TextFormatConformanceTestSuite::RunValidUnknownTextFormatTest( const string& test_name, const Message& message) { string serialized_input; @@ -201,276 +234,324 @@ void TextFormatConformanceTestSuite::RunValidUnknownTextFormatTest( } void TextFormatConformanceTestSuite::RunSuiteImpl() { - RunValidTextFormatTest("HelloWorld", REQUIRED, - "optional_string: 'Hello, World!'"); - // Integer fields. - RunValidTextFormatTest("Int32FieldMaxValue", REQUIRED, - "optional_int32: 2147483647"); - RunValidTextFormatTest("Int32FieldMinValue", REQUIRED, - "optional_int32: -2147483648"); - RunValidTextFormatTest("Uint32FieldMaxValue", REQUIRED, - "optional_uint32: 4294967295"); - RunValidTextFormatTest("Int64FieldMaxValue", REQUIRED, - "optional_int64: 9223372036854775807"); - RunValidTextFormatTest("Int64FieldMinValue", REQUIRED, - "optional_int64: -9223372036854775808"); - RunValidTextFormatTest("Uint64FieldMaxValue", REQUIRED, - "optional_uint64: 18446744073709551615"); - - // Parsers reject out-of-bound integer values. - ExpectParseFailure("Int32FieldTooLarge", REQUIRED, - "optional_int32: 2147483648"); - ExpectParseFailure("Int32FieldTooSmall", REQUIRED, - "optional_int32: -2147483649"); - ExpectParseFailure("Uint32FieldTooLarge", REQUIRED, - "optional_uint32: 4294967296"); - ExpectParseFailure("Int64FieldTooLarge", REQUIRED, - "optional_int64: 9223372036854775808"); - ExpectParseFailure("Int64FieldTooSmall", REQUIRED, - "optional_int64: -9223372036854775809"); - ExpectParseFailure("Uint64FieldTooLarge", REQUIRED, - "optional_uint64: 18446744073709551616"); - - // Floating point fields - RunValidTextFormatTest("FloatField", REQUIRED, - "optional_float: 3.192837"); - RunValidTextFormatTest("FloatFieldWithVeryPreciseNumber", REQUIRED, - "optional_float: 3.123456789123456789"); - RunValidTextFormatTest("FloatFieldMaxValue", REQUIRED, - "optional_float: 3.4028235e+38"); - RunValidTextFormatTest("FloatFieldMinValue", REQUIRED, - "optional_float: 1.17549e-38"); - RunValidTextFormatTest("FloatFieldNaNValue", REQUIRED, - "optional_float: NaN"); - RunValidTextFormatTest("FloatFieldPosInfValue", REQUIRED, - "optional_float: inf"); - RunValidTextFormatTest("FloatFieldNegInfValue", REQUIRED, - "optional_float: -inf"); - RunValidTextFormatTest("FloatFieldWithInt32Max", REQUIRED, - "optional_float: 4294967296"); - RunValidTextFormatTest("FloatFieldLargerThanInt64", REQUIRED, - "optional_float: 9223372036854775808"); - RunValidTextFormatTest("FloatFieldTooLarge", REQUIRED, - "optional_float: 3.4028235e+39"); - RunValidTextFormatTest("FloatFieldTooSmall", REQUIRED, - "optional_float: 1.17549e-39"); - RunValidTextFormatTest("FloatFieldLargerThanUint64", REQUIRED, - "optional_float: 18446744073709551616"); - - // String literals x {Strings, Bytes} - for (const auto& field_type : std::vector{"String", "Bytes"}) { - const std::string field_name = - field_type == "String" ? "optional_string" : "optional_bytes"; - RunValidTextFormatTest( - absl::StrCat("StringLiteralConcat", field_type), REQUIRED, - absl::StrCat(field_name, ": 'first' \"second\"\n'third'")); - RunValidTextFormatTest( - absl::StrCat("StringLiteralBasicEscapes", field_type), REQUIRED, - absl::StrCat(field_name, ": '\\a\\b\\f\\n\\r\\t\\v\\?\\\\\\'\\\"'")); - RunValidTextFormatTest( - absl::StrCat("StringLiteralOctalEscapes", field_type), REQUIRED, - absl::StrCat(field_name, ": '\\341\\210\\264'")); - RunValidTextFormatTest(absl::StrCat("StringLiteralHexEscapes", field_type), - REQUIRED, - absl::StrCat(field_name, ": '\\xe1\\x88\\xb4'")); - RunValidTextFormatTest( - absl::StrCat("StringLiteralShortUnicodeEscape", field_type), - RECOMMENDED, absl::StrCat(field_name, ": '\\u1234'")); - RunValidTextFormatTest( - absl::StrCat("StringLiteralLongUnicodeEscapes", field_type), - RECOMMENDED, absl::StrCat(field_name, ": '\\U00001234\\U00010437'")); - // String literals don't include line feeds. - ExpectParseFailure(absl::StrCat("StringLiteralIncludesLF", field_type), - REQUIRED, - absl::StrCat(field_name, ": 'first line\nsecond line'")); - // Unicode escapes don't include code points that lie beyond the planes - // (> 0x10ffff). - ExpectParseFailure( - absl::StrCat("StringLiteralLongUnicodeEscapeTooLarge", field_type), - REQUIRED, absl::StrCat(field_name, ": '\\U00110000'")); - // Unicode escapes don't include surrogates. - ExpectParseFailure( - absl::StrCat("StringLiteralShortUnicodeEscapeSurrogatePair", - field_type), - RECOMMENDED, absl::StrCat(field_name, ": '\\ud801\\udc37'")); - ExpectParseFailure( - absl::StrCat("StringLiteralShortUnicodeEscapeSurrogateFirstOnly", - field_type), - RECOMMENDED, absl::StrCat(field_name, ": '\\ud800'")); - ExpectParseFailure( - absl::StrCat("StringLiteralShortUnicodeEscapeSurrogateSecondOnly", - field_type), - RECOMMENDED, absl::StrCat(field_name, ": '\\udc00'")); - ExpectParseFailure( - absl::StrCat("StringLiteralLongUnicodeEscapeSurrogateFirstOnly", - field_type), - RECOMMENDED, absl::StrCat(field_name, ": '\\U0000d800'")); - ExpectParseFailure( - absl::StrCat("StringLiteralLongUnicodeEscapeSurrogateSecondOnly", - field_type), - RECOMMENDED, absl::StrCat(field_name, ": '\\U0000dc00'")); - ExpectParseFailure( - absl::StrCat("StringLiteralLongUnicodeEscapeSurrogatePair", field_type), - RECOMMENDED, absl::StrCat(field_name, ": '\\U0000d801\\U00000dc37'")); - ExpectParseFailure( - absl::StrCat("StringLiteralUnicodeEscapeSurrogatePairLongShort", - field_type), - RECOMMENDED, absl::StrCat(field_name, ": '\\U0000d801\\udc37'")); - ExpectParseFailure( - absl::StrCat("StringLiteralUnicodeEscapeSurrogatePairShortLong", - field_type), - RECOMMENDED, absl::StrCat(field_name, ": '\\ud801\\U0000dc37'")); - - // The following method depend on the type of field, as strings have extra - // validation. - const auto test_method = - field_type == "String" - ? &TextFormatConformanceTestSuite::ExpectParseFailure - : &TextFormatConformanceTestSuite::RunValidTextFormatTest; - - // String fields reject invalid UTF-8 byte sequences; bytes fields don't. - (this->*test_method)(absl::StrCat(field_type, "FieldBadUTF8Octal"), - REQUIRED, absl::StrCat(field_name, ": '\\300'")); - (this->*test_method)(absl::StrCat(field_type, "FieldBadUTF8Hex"), REQUIRED, - absl::StrCat(field_name, ": '\\xc0'")); - } + if (!performance_) { + RunValidTextFormatTest("HelloWorld", REQUIRED, + "optional_string: 'Hello, World!'"); + // Integer fields. + RunValidTextFormatTest("Int32FieldMaxValue", REQUIRED, + "optional_int32: 2147483647"); + RunValidTextFormatTest("Int32FieldMinValue", REQUIRED, + "optional_int32: -2147483648"); + RunValidTextFormatTest("Uint32FieldMaxValue", REQUIRED, + "optional_uint32: 4294967295"); + RunValidTextFormatTest("Int64FieldMaxValue", REQUIRED, + "optional_int64: 9223372036854775807"); + RunValidTextFormatTest("Int64FieldMinValue", REQUIRED, + "optional_int64: -9223372036854775808"); + RunValidTextFormatTest("Uint64FieldMaxValue", REQUIRED, + "optional_uint64: 18446744073709551615"); + + // Parsers reject out-of-bound integer values. + ExpectParseFailure("Int32FieldTooLarge", REQUIRED, + "optional_int32: 2147483648"); + ExpectParseFailure("Int32FieldTooSmall", REQUIRED, + "optional_int32: -2147483649"); + ExpectParseFailure("Uint32FieldTooLarge", REQUIRED, + "optional_uint32: 4294967296"); + ExpectParseFailure("Int64FieldTooLarge", REQUIRED, + "optional_int64: 9223372036854775808"); + ExpectParseFailure("Int64FieldTooSmall", REQUIRED, + "optional_int64: -9223372036854775809"); + ExpectParseFailure("Uint64FieldTooLarge", REQUIRED, + "optional_uint64: 18446744073709551616"); + + // Floating point fields + RunValidTextFormatTest("FloatField", REQUIRED, "optional_float: 3.192837"); + RunValidTextFormatTest("FloatFieldWithVeryPreciseNumber", REQUIRED, + "optional_float: 3.123456789123456789"); + RunValidTextFormatTest("FloatFieldMaxValue", REQUIRED, + "optional_float: 3.4028235e+38"); + RunValidTextFormatTest("FloatFieldMinValue", REQUIRED, + "optional_float: 1.17549e-38"); + RunValidTextFormatTest("FloatFieldNaNValue", REQUIRED, + "optional_float: NaN"); + RunValidTextFormatTest("FloatFieldPosInfValue", REQUIRED, + "optional_float: inf"); + RunValidTextFormatTest("FloatFieldNegInfValue", REQUIRED, + "optional_float: -inf"); + RunValidTextFormatTest("FloatFieldWithInt32Max", REQUIRED, + "optional_float: 4294967296"); + RunValidTextFormatTest("FloatFieldLargerThanInt64", REQUIRED, + "optional_float: 9223372036854775808"); + RunValidTextFormatTest("FloatFieldTooLarge", REQUIRED, + "optional_float: 3.4028235e+39"); + RunValidTextFormatTest("FloatFieldTooSmall", REQUIRED, + "optional_float: 1.17549e-39"); + RunValidTextFormatTest("FloatFieldLargerThanUint64", REQUIRED, + "optional_float: 18446744073709551616"); + + // String literals x {Strings, Bytes} + for (const auto& field_type : std::vector{"String", "Bytes"}) { + const std::string field_name = + field_type == "String" ? "optional_string" : "optional_bytes"; + RunValidTextFormatTest( + absl::StrCat("StringLiteralConcat", field_type), REQUIRED, + absl::StrCat(field_name, ": 'first' \"second\"\n'third'")); + RunValidTextFormatTest( + absl::StrCat("StringLiteralBasicEscapes", field_type), REQUIRED, + absl::StrCat(field_name, ": '\\a\\b\\f\\n\\r\\t\\v\\?\\\\\\'\\\"'")); + RunValidTextFormatTest( + absl::StrCat("StringLiteralOctalEscapes", field_type), REQUIRED, + absl::StrCat(field_name, ": '\\341\\210\\264'")); + RunValidTextFormatTest( + absl::StrCat("StringLiteralHexEscapes", field_type), REQUIRED, + absl::StrCat(field_name, ": '\\xe1\\x88\\xb4'")); + RunValidTextFormatTest( + absl::StrCat("StringLiteralShortUnicodeEscape", field_type), + RECOMMENDED, absl::StrCat(field_name, ": '\\u1234'")); + RunValidTextFormatTest( + absl::StrCat("StringLiteralLongUnicodeEscapes", field_type), + RECOMMENDED, absl::StrCat(field_name, ": '\\U00001234\\U00010437'")); + // String literals don't include line feeds. + ExpectParseFailure( + absl::StrCat("StringLiteralIncludesLF", field_type), REQUIRED, + absl::StrCat(field_name, ": 'first line\nsecond line'")); + // Unicode escapes don't include code points that lie beyond the planes + // (> 0x10ffff). + ExpectParseFailure( + absl::StrCat("StringLiteralLongUnicodeEscapeTooLarge", field_type), + REQUIRED, absl::StrCat(field_name, ": '\\U00110000'")); + // Unicode escapes don't include surrogates. + ExpectParseFailure( + absl::StrCat("StringLiteralShortUnicodeEscapeSurrogatePair", + field_type), + RECOMMENDED, absl::StrCat(field_name, ": '\\ud801\\udc37'")); + ExpectParseFailure( + absl::StrCat("StringLiteralShortUnicodeEscapeSurrogateFirstOnly", + field_type), + RECOMMENDED, absl::StrCat(field_name, ": '\\ud800'")); + ExpectParseFailure( + absl::StrCat("StringLiteralShortUnicodeEscapeSurrogateSecondOnly", + field_type), + RECOMMENDED, absl::StrCat(field_name, ": '\\udc00'")); + ExpectParseFailure( + absl::StrCat("StringLiteralLongUnicodeEscapeSurrogateFirstOnly", + field_type), + RECOMMENDED, absl::StrCat(field_name, ": '\\U0000d800'")); + ExpectParseFailure( + absl::StrCat("StringLiteralLongUnicodeEscapeSurrogateSecondOnly", + field_type), + RECOMMENDED, absl::StrCat(field_name, ": '\\U0000dc00'")); + ExpectParseFailure( + absl::StrCat("StringLiteralLongUnicodeEscapeSurrogatePair", + field_type), + RECOMMENDED, absl::StrCat(field_name, ": '\\U0000d801\\U00000dc37'")); + ExpectParseFailure( + absl::StrCat("StringLiteralUnicodeEscapeSurrogatePairLongShort", + field_type), + RECOMMENDED, absl::StrCat(field_name, ": '\\U0000d801\\udc37'")); + ExpectParseFailure( + absl::StrCat("StringLiteralUnicodeEscapeSurrogatePairShortLong", + field_type), + RECOMMENDED, absl::StrCat(field_name, ": '\\ud801\\U0000dc37'")); + + // The following method depend on the type of field, as strings have extra + // validation. + const auto test_method = + field_type == "String" + ? &TextFormatConformanceTestSuite::ExpectParseFailure + : &TextFormatConformanceTestSuite::RunValidTextFormatTest; + + // String fields reject invalid UTF-8 byte sequences; bytes fields don't. + (this->*test_method)(absl::StrCat(field_type, "FieldBadUTF8Octal"), + REQUIRED, absl::StrCat(field_name, ": '\\300'")); + (this->*test_method)(absl::StrCat(field_type, "FieldBadUTF8Hex"), + REQUIRED, absl::StrCat(field_name, ": '\\xc0'")); + } - // Group fields - RunValidTextFormatTestProto2("GroupFieldNoColon", REQUIRED, - "Data { group_int32: 1 }"); - RunValidTextFormatTestProto2("GroupFieldWithColon", REQUIRED, - "Data: { group_int32: 1 }"); - RunValidTextFormatTestProto2("GroupFieldEmpty", REQUIRED, - "Data {}"); - - - // Unknown Fields - UnknownToTestAllTypes message; - // Unable to print unknown Fixed32/Fixed64 fields as if they are known. - // Fixed32/Fixed64 fields are not added in the tests. - message.set_optional_int32(123); - message.set_optional_string("hello"); - message.set_optional_bool(true); - RunValidUnknownTextFormatTest("ScalarUnknownFields", message); - - message.Clear(); - message.mutable_nested_message()->set_c(111); - RunValidUnknownTextFormatTest("MessageUnknownFields", message); - - message.Clear(); - message.mutable_optionalgroup()->set_a(321); - RunValidUnknownTextFormatTest("GroupUnknownFields", message); - - message.add_repeated_int32(1); - message.add_repeated_int32(2); - message.add_repeated_int32(3); - RunValidUnknownTextFormatTest("RepeatedUnknownFields", message); - - // Any fields - RunValidTextFormatTest("AnyField", REQUIRED, - R"( - optional_any: { - [type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3] { - optional_int32: 12345 + // Group fields + RunValidTextFormatTestProto2("GroupFieldNoColon", REQUIRED, + "Data { group_int32: 1 }"); + RunValidTextFormatTestProto2("GroupFieldWithColon", REQUIRED, + "Data: { group_int32: 1 }"); + RunValidTextFormatTestProto2("GroupFieldEmpty", REQUIRED, "Data {}"); + + // Unknown Fields + UnknownToTestAllTypes message; + // Unable to print unknown Fixed32/Fixed64 fields as if they are known. + // Fixed32/Fixed64 fields are not added in the tests. + message.set_optional_int32(123); + message.set_optional_string("hello"); + message.set_optional_bool(true); + RunValidUnknownTextFormatTest("ScalarUnknownFields", message); + + message.Clear(); + message.mutable_nested_message()->set_c(111); + RunValidUnknownTextFormatTest("MessageUnknownFields", message); + + message.Clear(); + message.mutable_optionalgroup()->set_a(321); + RunValidUnknownTextFormatTest("GroupUnknownFields", message); + + message.add_repeated_int32(1); + message.add_repeated_int32(2); + message.add_repeated_int32(3); + RunValidUnknownTextFormatTest("RepeatedUnknownFields", message); + + // Any fields + RunValidTextFormatTest("AnyField", REQUIRED, + R"( + optional_any: { + [type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3] { + optional_int32: 12345 + } } - } - )"); - RunValidTextFormatTest("AnyFieldWithRawBytes", REQUIRED, - R"( - optional_any: { - type_url: "type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3" - value: "\b\271`" - } - )"); - ExpectParseFailure("AnyFieldWithInvalidType", REQUIRED, - R"( - optional_any: { - [type.googleapis.com/unknown] { - optional_int32: 12345 + )"); + RunValidTextFormatTest("AnyFieldWithRawBytes", REQUIRED, + R"( + optional_any: { + type_url: "type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3" + value: "\b\271`" } - } - )"); + )"); + ExpectParseFailure("AnyFieldWithInvalidType", REQUIRED, + R"( + optional_any: { + [type.googleapis.com/unknown] { + optional_int32: 12345 + } + } + )"); + + // Map fields + TestAllTypesProto3 prototype; + (*prototype.mutable_map_string_string())["c"] = "value"; + (*prototype.mutable_map_string_string())["b"] = "value"; + (*prototype.mutable_map_string_string())["a"] = "value"; + RunValidTextFormatTestWithMessage("AlphabeticallySortedMapStringKeys", + REQUIRED, + R"( + map_string_string { + key: "a" + value: "value" + } + map_string_string { + key: "b" + value: "value" + } + map_string_string { + key: "c" + value: "value" + } + )", + prototype); + + prototype.Clear(); + (*prototype.mutable_map_int32_int32())[3] = 0; + (*prototype.mutable_map_int32_int32())[2] = 0; + (*prototype.mutable_map_int32_int32())[1] = 0; + RunValidTextFormatTestWithMessage("AlphabeticallySortedMapIntKeys", + REQUIRED, + R"( + map_int32_int32 { + key: 1 + value: 0 + } + map_int32_int32 { + key: 2 + value: 0 + } + map_int32_int32 { + key: 3 + value: 0 + } + )", + prototype); + + prototype.Clear(); + (*prototype.mutable_map_bool_bool())[true] = false; + (*prototype.mutable_map_bool_bool())[false] = false; + RunValidTextFormatTestWithMessage("AlphabeticallySortedMapBoolKeys", + REQUIRED, + R"( + map_bool_bool { + key: false + value: false + } + map_bool_bool { + key: true + value: false + } + )", + prototype); + + prototype.Clear(); + ConformanceRequestSetting setting_map( + REQUIRED, conformance::TEXT_FORMAT, conformance::PROTOBUF, + conformance::TEXT_FORMAT_TEST, prototype, "DuplicateMapKey", R"( + map_string_nested_message { + key: "duplicate" + value: { a: 123 } + } + map_string_nested_message { + key: "duplicate" + value: { corecursive: {} } + } + )"); + // The last-specified value will be retained in a parsed map + RunValidInputTest(setting_map, R"( + map_string_nested_message { + key: "duplicate" + value: { corecursive: {} } + } + )"); + } + // Flag control performance tests to keep them internal and opt-in only + if (performance_) { + RunTextFormatPerformanceTests(); + } +} - // Map fields - TestAllTypesProto3 prototype; - (*prototype.mutable_map_string_string())["c"] = "value"; - (*prototype.mutable_map_string_string())["b"] = "value"; - (*prototype.mutable_map_string_string())["a"] = "value"; - RunValidTextFormatTestWithMessage("AlphabeticallySortedMapStringKeys", - REQUIRED, - R"( - map_string_string { - key: "a" - value: "value" - } - map_string_string { - key: "b" - value: "value" - } - map_string_string { - key: "c" - value: "value" - } - )", - prototype); +void TextFormatConformanceTestSuite::RunTextFormatPerformanceTests() { + TestTextFormatPerformanceMergeMessageWithRepeatedField("Bool", + "repeated_bool: true"); + TestTextFormatPerformanceMergeMessageWithRepeatedField( + "Double", "repeated_double: 123"); + TestTextFormatPerformanceMergeMessageWithRepeatedField( + "Int32", "repeated_uint32: 123"); + TestTextFormatPerformanceMergeMessageWithRepeatedField( + "Int64", "repeated_uint64: 123"); + TestTextFormatPerformanceMergeMessageWithRepeatedField( + "String", R"(repeated_string: "foo")"); + TestTextFormatPerformanceMergeMessageWithRepeatedField( + "Bytes", R"(repeated_bytes: "foo")"); +} - prototype.Clear(); - (*prototype.mutable_map_int32_int32())[3] = 0; - (*prototype.mutable_map_int32_int32())[2] = 0; - (*prototype.mutable_map_int32_int32())[1] = 0; - RunValidTextFormatTestWithMessage("AlphabeticallySortedMapIntKeys", REQUIRED, - R"( - map_int32_int32 { - key: 1 - value: 0 - } - map_int32_int32 { - key: 2 - value: 0 - } - map_int32_int32 { - key: 3 - value: 0 - } - )", - prototype); +// This is currently considered valid input by some languages but not others +void TextFormatConformanceTestSuite:: + TestTextFormatPerformanceMergeMessageWithRepeatedField( + const string& test_type_name, const string& message_field) { + string recursive_message = "recursive_message { " + message_field + " }"; - prototype.Clear(); - (*prototype.mutable_map_bool_bool())[true] = false; - (*prototype.mutable_map_bool_bool())[false] = false; - RunValidTextFormatTestWithMessage("AlphabeticallySortedMapBoolKeys", REQUIRED, - R"( - map_bool_bool { - key: false - value: false - } - map_bool_bool { - key: true - value: false - } - )", - prototype); + string input; + for (size_t i = 0; i < kPerformanceRepeatCount; i++) { + input.append(recursive_message); + } - prototype.Clear(); - ConformanceRequestSetting setting_map( - REQUIRED, conformance::TEXT_FORMAT, conformance::PROTOBUF, - conformance::TEXT_FORMAT_TEST, prototype, "DuplicateMapKey", R"( - map_string_nested_message { - key: "duplicate" - value: { a: 123 } - } - map_string_nested_message { - key: "duplicate" - value: { corecursive: {} } - } - )"); - // The last-specified value will be retained in a parsed map - RunValidInputTest(setting_map, R"( - map_string_nested_message { - key: "duplicate" - value: { corecursive: {} } - } - )"); + string expected = "recursive_message { "; + for (size_t i = 0; i < kPerformanceRepeatCount; i++) { + expected.append(message_field + " "); + } + expected.append("}"); + + RunValidTextFormatTestProto2WithExpected( + "TestTextFormatPerformanceMergeMessageWithRepeatedField" + + test_type_name + "Proto2", + RECOMMENDED, input, expected); + RunValidTextFormatTestWithExpected( + "TestTextFormatPerformanceMergeMessageWithRepeatedField" + + test_type_name + "Proto3", + RECOMMENDED, input, expected); } } // namespace protobuf diff --git a/conformance/text_format_conformance_suite.h b/conformance/text_format_conformance_suite.h index e875f3148e..e594cacc0c 100644 --- a/conformance/text_format_conformance_suite.h +++ b/conformance/text_format_conformance_suite.h @@ -42,15 +42,29 @@ class TextFormatConformanceTestSuite : public ConformanceTestSuite { private: void RunSuiteImpl() override; + void RunTextFormatPerformanceTests(); void RunValidTextFormatTest(const std::string& test_name, ConformanceLevel level, const std::string& input); void RunValidTextFormatTestProto2(const std::string& test_name, ConformanceLevel level, const std::string& input); + void RunValidTextFormatTestWithExpected(const std::string& test_name, + ConformanceLevel level, + const std::string& input, + const std::string& expected); + void RunValidTextFormatTestProto2WithExpected(const std::string& test_name, + ConformanceLevel level, + const std::string& input, + const std::string& expected); void RunValidTextFormatTestWithMessage(const std::string& test_name, ConformanceLevel level, const std::string& input_text, const Message& prototype); + void RunValidTextFormatTestWithMessage(const std::string& test_name, + ConformanceLevel level, + const std::string& input_text, + const std::string& expected_text, + const Message& prototype); void RunValidUnknownTextFormatTest(const std::string& test_name, const Message& message); void ExpectParseFailure(const std::string& test_name, ConformanceLevel level, @@ -61,6 +75,8 @@ class TextFormatConformanceTestSuite : public ConformanceTestSuite { bool ParseResponse(const conformance::ConformanceResponse& response, const ConformanceRequestSetting& setting, Message* test_message) override; + void TestTextFormatPerformanceMergeMessageWithRepeatedField( + const std::string& test_type_name, const std::string& message_field); }; } // namespace protobuf diff --git a/csharp/Google.Protobuf.Tools.nuspec b/csharp/Google.Protobuf.Tools.nuspec index 096d0a47c1..54a8d0cf82 100644 --- a/csharp/Google.Protobuf.Tools.nuspec +++ b/csharp/Google.Protobuf.Tools.nuspec @@ -5,7 +5,7 @@ Google Protocol Buffers tools Tools for Protocol Buffers - Google's data interchange format. See project site for more info. - 3.21.6 + 3.21.7 Google Inc. protobuf-packages https://github.com/protocolbuffers/protobuf/blob/main/LICENSE diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj index af93a2c6d9..016218c2a6 100644 --- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj +++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj @@ -4,7 +4,7 @@ C# runtime library for Protocol Buffers - Google's data interchange format. Copyright 2015, Google Inc. Google Protocol Buffers - 3.21.6 + 3.21.7 10.0 Google Inc. netstandard1.1;netstandard2.0;net45;net50 diff --git a/docs/cmake_protobuf_generate.md b/docs/cmake_protobuf_generate.md new file mode 100644 index 0000000000..d3e9110ebc --- /dev/null +++ b/docs/cmake_protobuf_generate.md @@ -0,0 +1,135 @@ +# How to use `protobuf_generate` + +This document explains how to use the function `protobuf_generate` which is provided by protobuf's CMake module. + +## Usage + +In the same directory that called `find_package(protobuf CONFIG)` and any of its subdirectories, the CMake function `protobuf_generate` is made available by +[`protobuf-generate.cmake`](../cmake/protobuf-generate.cmake). It can be used to automatically generate source files from `.proto` schema files at build time. + +### Basic example + +Let us see how `protobuf_generate` can be used to generate and compile the source files of a proto schema whenever an object target called `proto-objects` is built. + +Given the following directory structure: + +- `proto/helloworld/helloworld.proto` +- `CMakeLists.txt` + +where `helloworld.proto` is a protobuf schema file and `CMakeLists.txt` contains: + +```cmake +find_package(protobuf CONFIG REQUIRED) + +add_library(proto-objects OBJECT "${CMAKE_CURRENT_LIST_DIR}/proto/helloworld/helloworld.proto") + +target_link_libraries(proto-objects PUBLIC protobuf::libprotobuf) + +set(PROTO_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") + +target_include_directories(proto-objects PUBLIC "$") + +protobuf_generate( + TARGET proto-objects + IMPORT_DIRS "${CMAKE_CURRENT_LIST_DIR}/proto" + PROTOC_OUT_DIR "${PROTO_BINARY_DIR}") +``` + +Building the target `proto-objects` will generate the files: + +- `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.pb.h` +- `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.pb.cc` + +and (depending on the build system) output: + +```shell +[build] [1/2] Running cpp protocol buffer compiler on /proto/helloworld/helloworld.proto +[build] [2/2] Building CXX object /build/generated/helloworld/helloworld.pb.cc.o +``` + +### gRPC example + +`protobuf_generate` can also be customized to invoke plugins like gRPC's `grpc_cpp_plugin`. Given the same directory structure as in the [basic example](#basic-example) +and let `CMakeLists.txt` contain: + +```cmake +find_package(gRPC CONFIG REQUIRED) + +add_library(proto-objects OBJECT "${CMAKE_CURRENT_LIST_DIR}/proto/helloworld/helloworld.proto") + +target_link_libraries(proto-objects PUBLIC protobuf::libprotobuf gRPC::grpc++) + +set(PROTO_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") +set(PROTO_IMPORT_DIRS "${CMAKE_CURRENT_LIST_DIR}/proto") + +target_include_directories(proto-objects PUBLIC "$") + +protobuf_generate( + TARGET proto-objects + IMPORT_DIRS ${PROTO_IMPORT_DIRS} + PROTOC_OUT_DIR "${PROTO_BINARY_DIR}") + +protobuf_generate( + TARGET proto-objects + LANGUAGE grpc + GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc + PLUGIN "protoc-gen-grpc=\$" + IMPORT_DIRS ${PROTO_IMPORT_DIRS} + PROTOC_OUT_DIR "${PROTO_BINARY_DIR}") +``` + +Then building `proto-objects` will generate and compile: + +- `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.pb.h` +- `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.pb.cc` +- `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.grpc.pb.h` +- `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.grpc.pb.cc` + +And `protoc` will automatically be re-run whenever the schema files change and `proto-objects` is built. + +### Note on unity builds + +Since protobuf's generated source files are unsuited for [jumbo/unity builds](https://cmake.org/cmake/help/latest/prop_tgt/UNITY_BUILD.html) it is recommended +to exclude them from such builds which can be achieved by adjusting their properties: + +```cmake +protobuf_generate( + OUT_VAR PROTO_GENERATED_FILES + ...) + +set_source_files_properties(${PROTO_GENERATED_FILES} PROPERTIES SKIP_UNITY_BUILD_INCLUSION on) +``` + +## How it works + +For each source file ending in `proto` of the argument provided to `TARGET` or each file provided through `PROTOS`, `protobuf_generate` will set up +a [add_custom_command](https://cmake.org/cmake/help/latest/command/add_custom_command.html) which depends on `protobuf::protoc` and the proto files. +It declares the generated source files as `OUTPUT` which means that any target that depends on them will automatically cause the custom command to execute +when it is brought up to date. The command itself is made up of the arguments for `protoc`, like the output directory, the schema files, the language to +generate for, the plugins to use, etc. + +## Reference + +Arguments accepted by `protobuf_generate`. + +Flag arguments: + +- `APPEND_PATH` — A flag that causes the base path of all proto schema files to be added to `IMPORT_DIRS`. + +Single-value arguments: + +- `LANGUAGE` — A single value: cpp or python. Determines what kind of source files are being generated. +- `OUT_VAR` — Name of a CMake variable that will be filled with the paths to the generated source files. +- `EXPORT_MACRO` — Name of a macro that is applied to all generated Protobuf message classes and extern variables. It can, for example, be used to declare DLL exports. +- `PROTOC_OUT_DIR` — Output directory of generated source files. Defaults to `CMAKE_CURRENT_BINARY_DIR`. +- `PLUGIN` — An optional plugin executable. This could, for example, be the path to `grpc_cpp_plugin`. +- `PLUGIN_OPTIONS` — Additional options provided to the plugin, such as `generate_mock_code=true` for the gRPC cpp plugin. +- `DEPENDENCIES` — Arguments forwarded to the `DEPENDS` of the underlying `add_custom_command` invocation. +- `TARGET` — CMake target that will have the generated files added as sources. + +Multi-value arguments: + +- `PROTOS` — List of proto schema files. If omitted, then every source file ending in *proto* of `TARGET` will be used. +- `IMPORT_DIRS` — A common parent directory for the schema files. For example, if the schema file is `proto/helloworld/helloworld.proto` and the import directory `proto/` then the generated files are `${PROTOC_OUT_DIR}/helloworld/helloworld.pb.h` and `${PROTOC_OUT_DIR}/helloworld/helloworld.pb.cc`. +- `GENERATE_EXTENSIONS` — If LANGUAGE is omitted then this must be set to the extensions that protoc generates. +- `PROTOC_OPTIONS` — Additional arguments that are forwarded to protoc. \ No newline at end of file diff --git a/java/README.md b/java/README.md index 6a23c0d9e8..0b56993b36 100644 --- a/java/README.md +++ b/java/README.md @@ -23,7 +23,7 @@ If you are using Maven, use the following: com.google.protobuf protobuf-java - 3.21.6 + 3.21.7 ``` @@ -37,7 +37,7 @@ protobuf-java-util package: com.google.protobuf protobuf-java-util - 3.21.6 + 3.21.7 ``` @@ -45,7 +45,7 @@ protobuf-java-util package: If you are using Gradle, add the following to your `build.gradle` file's dependencies: ``` - implementation 'com.google.protobuf:protobuf-java:3.21.6' + implementation 'com.google.protobuf:protobuf-java:3.21.7' ``` Again, be sure to check that the version number matches (or is newer than) the version number of protoc that you are using. diff --git a/java/bom/pom.xml b/java/bom/pom.xml index 1196d3685c..dc655626c3 100644 --- a/java/bom/pom.xml +++ b/java/bom/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-bom - 3.21.6 + 3.21.7 pom Protocol Buffers [BOM] diff --git a/java/core/pom.xml b/java/core/pom.xml index 7e5e8df1d7..a6da8c850e 100644 --- a/java/core/pom.xml +++ b/java/core/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.6 + 3.21.7 protobuf-java diff --git a/java/core/src/main/java/com/google/protobuf/FieldSet.java b/java/core/src/main/java/com/google/protobuf/FieldSet.java index b64f63b351..9b294e33a7 100644 --- a/java/core/src/main/java/com/google/protobuf/FieldSet.java +++ b/java/core/src/main/java/com/google/protobuf/FieldSet.java @@ -728,6 +728,10 @@ final class FieldSet> { if (descriptor.isRepeated()) { final List valueList = (List) value; if (descriptor.isPacked()) { + if (valueList.isEmpty()) { + // The tag should not be written for empty packed fields. + return; + } output.writeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED); // Compute the total data size so the length can be written. int dataSize = 0; @@ -893,9 +897,13 @@ final class FieldSet> { WireFormat.FieldType type = descriptor.getLiteType(); int number = descriptor.getNumber(); if (descriptor.isRepeated()) { + List valueList = (List) value; if (descriptor.isPacked()) { + if (valueList.isEmpty()) { + return 0; + } int dataSize = 0; - for (final Object element : (List) value) { + for (final Object element : valueList) { dataSize += computeElementSizeNoTag(type, element); } return dataSize @@ -903,7 +911,7 @@ final class FieldSet> { + CodedOutputStream.computeUInt32SizeNoTag(dataSize); } else { int size = 0; - for (final Object element : (List) value) { + for (final Object element : valueList) { size += computeElementSize(type, number, element); } return size; diff --git a/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java b/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java index 8e1abc0450..abe7cafa79 100644 --- a/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java +++ b/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java @@ -44,6 +44,7 @@ import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage; import protobuf_unittest.UnittestProto.TestEmptyMessage; import protobuf_unittest.UnittestProto.TestPackedTypes; +import java.util.ArrayList; import org.junit.Test; import org.junit.function.ThrowingRunnable; import org.junit.runner.RunWith; @@ -230,6 +231,19 @@ public class DynamicMessageTest { assertThat(rawBytes).isEqualTo(TestUtil.getPackedSet().toByteString()); } + @Test + public void testDynamicMessagePackedEmptySerialization() throws Exception { + Message message = + DynamicMessage.newBuilder(TestPackedTypes.getDescriptor()) + .setField( + TestPackedTypes.getDescriptor() + .findFieldByNumber(TestPackedTypes.PACKED_INT64_FIELD_NUMBER), + new ArrayList()) + .build(); + + assertThat(message.toByteString()).isEqualTo(ByteString.EMPTY); + } + @Test public void testDynamicMessagePackedParsing() throws Exception { TestPackedTypes.Builder builder = TestPackedTypes.newBuilder(); diff --git a/java/internal/testing.bzl b/java/internal/testing.bzl index 76e1e45170..b2a781baba 100644 --- a/java/internal/testing.bzl +++ b/java/internal/testing.bzl @@ -50,7 +50,7 @@ def junit_tests(name, srcs, data = [], deps = [], package_name = "com.google.pro if not test_name.endswith("Test") or test_name.startswith("Abstract"): continue if test_prefix: - test_name = "%s%s" % (test_prefix, test_name) + test_name = "%s%s" % (test_prefix, test_name) test_names = test_names + [test_name] suite_name = prefix + '_' + test_name _gen_suite( diff --git a/java/kotlin-lite/pom.xml b/java/kotlin-lite/pom.xml index 52bc1b3675..1b856dffa5 100644 --- a/java/kotlin-lite/pom.xml +++ b/java/kotlin-lite/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.6 + 3.21.7 protobuf-kotlin-lite diff --git a/java/kotlin/pom.xml b/java/kotlin/pom.xml index bc935c8c23..0177a7247b 100644 --- a/java/kotlin/pom.xml +++ b/java/kotlin/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.6 + 3.21.7 protobuf-kotlin diff --git a/java/lite.md b/java/lite.md index 6f003ed543..bd9c5a5bb8 100644 --- a/java/lite.md +++ b/java/lite.md @@ -29,7 +29,7 @@ protobuf Java Lite runtime. If you are using Maven, include the following: com.google.protobuf protobuf-javalite - 3.21.6 + 3.21.7 ``` diff --git a/java/lite/pom.xml b/java/lite/pom.xml index ba65f5cbf4..a78ff979b3 100644 --- a/java/lite/pom.xml +++ b/java/lite/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.6 + 3.21.7 protobuf-javalite diff --git a/java/pom.xml b/java/pom.xml index 197e7cd584..8b304fa570 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.6 + 3.21.7 pom Protocol Buffers [Parent] diff --git a/java/protoc/README.md b/java/protoc/README.md new file mode 100644 index 0000000000..a31ffbe822 --- /dev/null +++ b/java/protoc/README.md @@ -0,0 +1,42 @@ +# Publish pre-compiled protoc artifacts +``protoc`` is the compiler for ``.proto`` files. It generates language bindings +for the messages and/or RPC services from ``.proto`` files. + +Because ``protoc`` is a native executable, the scripts under this directory +publish a ``protoc`` executable (a.k.a. artifact) to Maven repositories. The +artifact can be used by build automation tools so that users would not need to +compile and install ``protoc`` for their systems. + +If you would like us to publish protoc artifact for a new platform, please +open an issue to request it. + +## Maven Location +The published protoc artifacts are available on Maven here: + + https://repo.maven.apache.org/maven2/com/google/protobuf/protoc/ + +## Versioning +The version of the ``protoc`` artifact must be the same as the version of the +Protobuf project. + +## Artifact name +The name of a published ``protoc`` artifact is in the following format: +``protoc---.exe``, e.g., ``protoc-3.6.1-linux-x86_64.exe``. + +Note that artifacts for linux/macos also have the `.exe` suffix but they are +not windows binaries. + +## System requirement +Install [Apache Maven](http://maven.apache.org/) if you don't have it. + +The scripts only work under Unix-like environments, e.g., Linux, MacOSX, and +Cygwin or MinGW for Windows. Please see ``README.md`` of the Protobuf project +for how to set up the build environment. + +## Tested build environments +We have successfully built artifacts on the following environments: +- Linux x86_32 and x86_64: + - Centos 6.9 (within Docker 1.6.1) + - Ubuntu 14.04.5 64-bit +- Linux aarch_64: Cross compiled with `g++-aarch64-linux-gnu` on Ubuntu 14.04.5 64-bit +- Mac OS X x86_32 and x86_64: Mac OS X 10.9.5 diff --git a/java/util/pom.xml b/java/util/pom.xml index 0f02bb84df..31fcbf269b 100644 --- a/java/util/pom.xml +++ b/java/util/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.6 + 3.21.7 protobuf-java-util diff --git a/java/util/src/main/java/com/google/protobuf/util/Values.java b/java/util/src/main/java/com/google/protobuf/util/Values.java index f03d70e0dc..370aafa5e4 100644 --- a/java/util/src/main/java/com/google/protobuf/util/Values.java +++ b/java/util/src/main/java/com/google/protobuf/util/Values.java @@ -75,10 +75,7 @@ public final class Values { * element in the iterable. */ public static Value of(Iterable values) { - Value.Builder valueBuilder = Value.newBuilder(); - ListValue.Builder listValue = valueBuilder.getListValueBuilder(); - listValue.addAllValues(values); - return valueBuilder.build(); + return Value.newBuilder().setListValue(ListValue.newBuilder().addAllValues(values)).build(); } private Values() {} diff --git a/kokoro/linux/aarch64/python_run_tests_with_qemu_aarch64.sh b/kokoro/linux/aarch64/python_run_tests_with_qemu_aarch64.sh index 0a62cff532..4c75ad8110 100755 --- a/kokoro/linux/aarch64/python_run_tests_with_qemu_aarch64.sh +++ b/kokoro/linux/aarch64/python_run_tests_with_qemu_aarch64.sh @@ -7,7 +7,7 @@ cd $(dirname $0)/../../.. cd python PYTHON="/opt/python/cp38-cp38/bin/python" -${PYTHON} -m pip install --user pytest auditwheel +${PYTHON} -m pip install --user pytest auditwheel numpy # check that we are really using aarch64 python (${PYTHON} -c 'import sysconfig; print(sysconfig.get_platform())' | grep -q "linux-aarch64") || (echo "Wrong python platform, needs to be aarch64 python."; exit 1) diff --git a/kokoro/linux/bazel.sh b/kokoro/linux/bazel.sh index b7c8000dc1..d97bb3b005 100755 --- a/kokoro/linux/bazel.sh +++ b/kokoro/linux/bazel.sh @@ -8,7 +8,6 @@ fi cd $(dirname $0)/../.. GIT_REPO_ROOT=`pwd` -rm -rf $GIT_REPO_ROOT/logs ENVS=() @@ -25,20 +24,38 @@ if [ -n "$BAZEL_ENV" ]; then done fi -tmpfile=$(mktemp -u) - -docker run \ - --cidfile $tmpfile \ - -v $GIT_REPO_ROOT:/workspace \ - $CONTAINER_IMAGE \ - test \ - --keep_going \ - --test_output=streamed \ - ${ENVS[@]} \ - $PLATFORM_CONFIG \ - $BAZEL_EXTRA_FLAGS \ - $BAZEL_TARGETS - -# Save logs for Kokoro -docker cp \ - `cat $tmpfile`:/workspace/logs $KOKORO_ARTIFACTS_DIR +function run { + local CONFIG=$1 + local BAZEL_CONFIG=$2 + + tmpfile=$(mktemp -u) + + rm -rf $GIT_REPO_ROOT/bazel-out $GIT_REPO_ROOT/bazel-bin + rm -rf $GIT_REPO_ROOT/logs + + docker run \ + --cidfile $tmpfile \ + --cap-add=SYS_PTRACE \ + -v $GIT_REPO_ROOT:/workspace \ + $CONTAINER_IMAGE \ + test \ + --keep_going \ + --test_output=streamed \ + ${ENVS[@]} \ + $PLATFORM_CONFIG \ + $BAZEL_CONFIG \ + $BAZEL_EXTRA_FLAGS \ + $BAZEL_TARGETS + + # Save logs for Kokoro + docker cp \ + `cat $tmpfile`:/workspace/logs $KOKORO_ARTIFACTS_DIR/$CONFIG +} + +if [ -n "$BAZEL_CONFIGS" ]; then + for config in $BAZEL_CONFIGS; do + run $config "--config=$config" + done +else + run +fi diff --git a/kokoro/linux/bazel/common.cfg b/kokoro/linux/bazel/common.cfg index cd41cb2cb8..54447d9a98 100644 --- a/kokoro/linux/bazel/common.cfg +++ b/kokoro/linux/bazel/common.cfg @@ -2,13 +2,28 @@ # Location of the build script in repository build_file: "protobuf/kokoro/linux/bazel.sh" -timeout_mins: 15 +timeout_mins: 120 + +env_vars { + key: "CONTAINER_IMAGE" + value: "gcr.io/protobuf-build/bazel/linux-san:b6bfa3bb505e83f062af0cb0ed23abf1e89b9edb" +} env_vars { key: "BAZEL_TARGETS" value: "//src/... @com_google_protobuf_examples//..." } +env_vars { + key: "BAZEL_CONFIGS" + value: "opt dbg asan kokoro-msan tsan ubsan" +} + +env_vars { + key: "BAZEL_EXTRA_FLAGS" + value: "--distinct_host_configuration=false" +} + action { define_artifacts { regex: "**/sponge_log.*" diff --git a/kokoro/linux/staleness/release.cfg b/kokoro/linux/staleness/release.cfg new file mode 100644 index 0000000000..d109c50399 --- /dev/null +++ b/kokoro/linux/staleness/release.cfg @@ -0,0 +1,18 @@ +# We run our staleness tests as release-type jobs only. They are not really +# part of the release process, but the release job type allows us to run the +# tests on a schedule only (not presubmit or postsubmit). + +# Location of the build script in repository +build_file: "protobuf/kokoro/linux/bazel.sh" +timeout_mins: 15 + +env_vars { + key: "BAZEL_TARGETS" + value: "//src:cmake_lists_staleness_test" +} + +action { + define_artifacts { + regex: "**/sponge_log.*" + } +} diff --git a/kokoro/macos/prepare_build_macos_rc b/kokoro/macos/prepare_build_macos_rc index fe3b6be0de..d8b1395164 100755 --- a/kokoro/macos/prepare_build_macos_rc +++ b/kokoro/macos/prepare_build_macos_rc @@ -8,7 +8,7 @@ export HOMEBREW_PREFIX=$(brew --prefix) ## # Select Xcode version -export DEVELOPER_DIR=/Applications/Xcode_13.3.1.app/Contents/Developer +export DEVELOPER_DIR=/Applications/Xcode_14.app/Contents/Developer sudo xcode-select -s "${DEVELOPER_DIR}" ## diff --git a/kokoro/release/protoc/build-protoc.sh b/kokoro/release/protoc/build-protoc.sh index d304d5f419..c0785eee4a 100755 --- a/kokoro/release/protoc/build-protoc.sh +++ b/kokoro/release/protoc/build-protoc.sh @@ -233,7 +233,7 @@ TARGET_FILE="target/$OS/$ARCH/$BAZEL_TARGET.exe" DOCKER_IMAGE=gcr.io/protobuf-build/bazel/linux@sha256:2bfd061284eff8234f2fcca16d71d43c69ccf3a22206628b54c204a6a9aac277 tmpfile=$(mktemp -u) && -docker run --cidfile $tmpfile -v $WORKING_DIR/..:/workspace $DOCKER_IMAGE \ +docker run --cidfile $tmpfile -v $WORKING_DIR/../../..:/workspace $DOCKER_IMAGE \ build //:$BAZEL_TARGET "${BAZEL_ARGS[@]}" && mkdir -p $(dirname $TARGET_FILE) && docker cp \ diff --git a/kokoro/windows/bazel/build.bat b/kokoro/windows/bazel/build.bat index 55fba16579..9b4e448f18 100644 --- a/kokoro/windows/bazel/build.bat +++ b/kokoro/windows/bazel/build.bat @@ -10,7 +10,7 @@ fsutil 8dot3name set 0 @rem Reinstall Bazel due to corrupt installation in kokoro. bazel version -choco install bazel -y -i +choco install bazel -y -i --version 5.1.0 bazel version @rem Make paths as short as possible to avoid long path issues. diff --git a/objectivec/DevTools/check_version_stamps.sh b/objectivec/DevTools/check_version_stamps.sh index a3524cb39d..5972e35fb5 100755 --- a/objectivec/DevTools/check_version_stamps.sh +++ b/objectivec/DevTools/check_version_stamps.sh @@ -16,7 +16,7 @@ die() { exit 1 } -readonly GeneratorSrc="${ProtoRootDir}/src/google/protobuf/compiler/objectivec/objectivec_file.cc" +readonly GeneratorSrc="${ProtoRootDir}/src/google/protobuf/compiler/objectivec/file.cc" readonly RuntimeSrc="${ProtoRootDir}/objectivec/GPBBootstrap.h" check_constant() { diff --git a/objectivec/GPBAny.pbobjc.h b/objectivec/GPBAny.pbobjc.h index e30acc0aec..3f40181ae6 100644 --- a/objectivec/GPBAny.pbobjc.h +++ b/objectivec/GPBAny.pbobjc.h @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/any.proto - // clang-format off +// source: google/protobuf/any.proto #import "GPBDescriptor.h" #import "GPBMessage.h" diff --git a/objectivec/GPBAny.pbobjc.m b/objectivec/GPBAny.pbobjc.m index e838675145..7f62f119e2 100644 --- a/objectivec/GPBAny.pbobjc.m +++ b/objectivec/GPBAny.pbobjc.m @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/any.proto - // clang-format off +// source: google/protobuf/any.proto #import "GPBProtocolBuffers_RuntimeSupport.h" #import "GPBAny.pbobjc.h" @@ -101,4 +100,4 @@ typedef struct GPBAny__storage_ { // @@protoc_insertion_point(global_scope) -// clange-format on +// clang-format on diff --git a/objectivec/GPBApi.pbobjc.h b/objectivec/GPBApi.pbobjc.h index 3cd0821bac..11b5400ea6 100644 --- a/objectivec/GPBApi.pbobjc.h +++ b/objectivec/GPBApi.pbobjc.h @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/api.proto - // clang-format off +// source: google/protobuf/api.proto #import "GPBDescriptor.h" #import "GPBMessage.h" diff --git a/objectivec/GPBApi.pbobjc.m b/objectivec/GPBApi.pbobjc.m index 88a215eb15..18c4c644e9 100644 --- a/objectivec/GPBApi.pbobjc.m +++ b/objectivec/GPBApi.pbobjc.m @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/api.proto - // clang-format off +// source: google/protobuf/api.proto #import "GPBProtocolBuffers_RuntimeSupport.h" #import "GPBApi.pbobjc.h" @@ -355,4 +354,4 @@ typedef struct GPBMixin__storage_ { // @@protoc_insertion_point(global_scope) -// clange-format on +// clang-format on diff --git a/objectivec/GPBDescriptor.m b/objectivec/GPBDescriptor.m index 72368cefda..316ce76a6c 100644 --- a/objectivec/GPBDescriptor.m +++ b/objectivec/GPBDescriptor.m @@ -681,7 +681,7 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) { } // The logic here has to match SetCommonFieldVariables() from - // objectivec_field.cc in the proto compiler. + // objectivec/field.cc in the proto compiler. NSString *name = self.name; NSUInteger len = [name length]; @@ -918,7 +918,7 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) { if (extraTextFormatInfo_) { result = GPBDecodeTextFormatName(extraTextFormatInfo_, (int32_t)index, shortName); } - // Logic here needs to match what objectivec_enum.cc does in the proto + // Logic here needs to match what objectivec/enum.cc does in the proto // compiler. if (result == nil) { NSUInteger len = [shortName length]; diff --git a/objectivec/GPBDuration.pbobjc.h b/objectivec/GPBDuration.pbobjc.h index fda9b4733f..7fb2658d5f 100644 --- a/objectivec/GPBDuration.pbobjc.h +++ b/objectivec/GPBDuration.pbobjc.h @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/duration.proto - // clang-format off +// source: google/protobuf/duration.proto #import "GPBDescriptor.h" #import "GPBMessage.h" diff --git a/objectivec/GPBDuration.pbobjc.m b/objectivec/GPBDuration.pbobjc.m index bc610923f4..06f5bc31d5 100644 --- a/objectivec/GPBDuration.pbobjc.m +++ b/objectivec/GPBDuration.pbobjc.m @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/duration.proto - // clang-format off +// source: google/protobuf/duration.proto #import "GPBProtocolBuffers_RuntimeSupport.h" #import "GPBDuration.pbobjc.h" @@ -96,4 +95,4 @@ typedef struct GPBDuration__storage_ { // @@protoc_insertion_point(global_scope) -// clange-format on +// clang-format on diff --git a/objectivec/GPBEmpty.pbobjc.h b/objectivec/GPBEmpty.pbobjc.h index 26ef9a6907..1c840eb6fd 100644 --- a/objectivec/GPBEmpty.pbobjc.h +++ b/objectivec/GPBEmpty.pbobjc.h @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/empty.proto - // clang-format off +// source: google/protobuf/empty.proto #import "GPBDescriptor.h" #import "GPBMessage.h" diff --git a/objectivec/GPBEmpty.pbobjc.m b/objectivec/GPBEmpty.pbobjc.m index 49f703099a..2360c369f3 100644 --- a/objectivec/GPBEmpty.pbobjc.m +++ b/objectivec/GPBEmpty.pbobjc.m @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/empty.proto - // clang-format off +// source: google/protobuf/empty.proto #import "GPBProtocolBuffers_RuntimeSupport.h" #import "GPBEmpty.pbobjc.h" @@ -72,4 +71,4 @@ typedef struct GPBEmpty__storage_ { // @@protoc_insertion_point(global_scope) -// clange-format on +// clang-format on diff --git a/objectivec/GPBFieldMask.pbobjc.h b/objectivec/GPBFieldMask.pbobjc.h index 87898ad254..5d4f59c45a 100644 --- a/objectivec/GPBFieldMask.pbobjc.h +++ b/objectivec/GPBFieldMask.pbobjc.h @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/field_mask.proto - // clang-format off +// source: google/protobuf/field_mask.proto #import "GPBDescriptor.h" #import "GPBMessage.h" diff --git a/objectivec/GPBFieldMask.pbobjc.m b/objectivec/GPBFieldMask.pbobjc.m index f820fd826d..acb202d35c 100644 --- a/objectivec/GPBFieldMask.pbobjc.m +++ b/objectivec/GPBFieldMask.pbobjc.m @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/field_mask.proto - // clang-format off +// source: google/protobuf/field_mask.proto #import "GPBProtocolBuffers_RuntimeSupport.h" #import "GPBFieldMask.pbobjc.h" @@ -85,4 +84,4 @@ typedef struct GPBFieldMask__storage_ { // @@protoc_insertion_point(global_scope) -// clange-format on +// clang-format on diff --git a/objectivec/GPBSourceContext.pbobjc.h b/objectivec/GPBSourceContext.pbobjc.h index e747dc0b9f..84338824d8 100644 --- a/objectivec/GPBSourceContext.pbobjc.h +++ b/objectivec/GPBSourceContext.pbobjc.h @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/source_context.proto - // clang-format off +// source: google/protobuf/source_context.proto #import "GPBDescriptor.h" #import "GPBMessage.h" diff --git a/objectivec/GPBSourceContext.pbobjc.m b/objectivec/GPBSourceContext.pbobjc.m index 094f32380a..7f035e71e3 100644 --- a/objectivec/GPBSourceContext.pbobjc.m +++ b/objectivec/GPBSourceContext.pbobjc.m @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/source_context.proto - // clang-format off +// source: google/protobuf/source_context.proto #import "GPBProtocolBuffers_RuntimeSupport.h" #import "GPBSourceContext.pbobjc.h" @@ -85,4 +84,4 @@ typedef struct GPBSourceContext__storage_ { // @@protoc_insertion_point(global_scope) -// clange-format on +// clang-format on diff --git a/objectivec/GPBStruct.pbobjc.h b/objectivec/GPBStruct.pbobjc.h index eaa531ed9a..4035f5166e 100644 --- a/objectivec/GPBStruct.pbobjc.h +++ b/objectivec/GPBStruct.pbobjc.h @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/struct.proto - // clang-format off +// source: google/protobuf/struct.proto #import "GPBDescriptor.h" #import "GPBMessage.h" diff --git a/objectivec/GPBStruct.pbobjc.m b/objectivec/GPBStruct.pbobjc.m index 3707178eb8..b6ee9c1e4b 100644 --- a/objectivec/GPBStruct.pbobjc.m +++ b/objectivec/GPBStruct.pbobjc.m @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/struct.proto - // clang-format off +// source: google/protobuf/struct.proto #import "GPBProtocolBuffers_RuntimeSupport.h" #import "GPBStruct.pbobjc.h" @@ -298,4 +297,4 @@ typedef struct GPBListValue__storage_ { // @@protoc_insertion_point(global_scope) -// clange-format on +// clang-format on diff --git a/objectivec/GPBTimestamp.pbobjc.h b/objectivec/GPBTimestamp.pbobjc.h index 6d6a93028f..0f1acdd8c2 100644 --- a/objectivec/GPBTimestamp.pbobjc.h +++ b/objectivec/GPBTimestamp.pbobjc.h @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/timestamp.proto - // clang-format off +// source: google/protobuf/timestamp.proto #import "GPBDescriptor.h" #import "GPBMessage.h" diff --git a/objectivec/GPBTimestamp.pbobjc.m b/objectivec/GPBTimestamp.pbobjc.m index 1792ecb3ab..7d2276c586 100644 --- a/objectivec/GPBTimestamp.pbobjc.m +++ b/objectivec/GPBTimestamp.pbobjc.m @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/timestamp.proto - // clang-format off +// source: google/protobuf/timestamp.proto #import "GPBProtocolBuffers_RuntimeSupport.h" #import "GPBTimestamp.pbobjc.h" @@ -96,4 +95,4 @@ typedef struct GPBTimestamp__storage_ { // @@protoc_insertion_point(global_scope) -// clange-format on +// clang-format on diff --git a/objectivec/GPBType.pbobjc.h b/objectivec/GPBType.pbobjc.h index ef9b74bf5f..b102ab48c2 100644 --- a/objectivec/GPBType.pbobjc.h +++ b/objectivec/GPBType.pbobjc.h @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/type.proto - // clang-format off +// source: google/protobuf/type.proto #import "GPBDescriptor.h" #import "GPBMessage.h" diff --git a/objectivec/GPBType.pbobjc.m b/objectivec/GPBType.pbobjc.m index 5c8c73e169..60f7c08944 100644 --- a/objectivec/GPBType.pbobjc.m +++ b/objectivec/GPBType.pbobjc.m @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/type.proto - // clang-format off +// source: google/protobuf/type.proto #import "GPBProtocolBuffers_RuntimeSupport.h" #import "GPBType.pbobjc.h" @@ -710,4 +709,4 @@ typedef struct GPBOption__storage_ { // @@protoc_insertion_point(global_scope) -// clange-format on +// clang-format on diff --git a/objectivec/GPBWrappers.pbobjc.h b/objectivec/GPBWrappers.pbobjc.h index 11b052a6ba..94e69ad417 100644 --- a/objectivec/GPBWrappers.pbobjc.h +++ b/objectivec/GPBWrappers.pbobjc.h @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/wrappers.proto - // clang-format off +// source: google/protobuf/wrappers.proto #import "GPBDescriptor.h" #import "GPBMessage.h" diff --git a/objectivec/GPBWrappers.pbobjc.m b/objectivec/GPBWrappers.pbobjc.m index 45ee1a3b94..879579cf05 100644 --- a/objectivec/GPBWrappers.pbobjc.m +++ b/objectivec/GPBWrappers.pbobjc.m @@ -1,7 +1,6 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/wrappers.proto - // clang-format off +// source: google/protobuf/wrappers.proto #import "GPBProtocolBuffers_RuntimeSupport.h" #import "GPBWrappers.pbobjc.h" @@ -444,4 +443,4 @@ typedef struct GPBBytesValue__storage_ { // @@protoc_insertion_point(global_scope) -// clange-format on +// clang-format on diff --git a/objectivec/Tests/GPBMessageTests.m b/objectivec/Tests/GPBMessageTests.m index 83b8d1172d..7d4cf79c3d 100644 --- a/objectivec/Tests/GPBMessageTests.m +++ b/objectivec/Tests/GPBMessageTests.m @@ -1843,8 +1843,8 @@ } - (void)testPropertyNaming { - // objectivec_helpers.cc has some special handing to get proper all caps - // for a few cases to meet objc developer expectations. + // names.cc has some special handing to get proper all caps for a few cases to + // meet objc developer expectations. // // This "test" confirms that the expected names are generated, otherwise the // test itself will fail to compile. @@ -1861,7 +1861,7 @@ } - (void)testEnumNaming { - // objectivec_helpers.cc has some interesting cases to deal with in + // names.cc has some interesting cases to deal with in // EnumValueName/EnumValueShortName. Confirm that things generated as // expected. @@ -1966,9 +1966,8 @@ } - (void)testReservedWordNaming { - // objectivec_helpers.cc has some special handing to make sure that - // some "reserved" objc names get renamed in a way so they - // don't conflict. + // names.cc has some special handing to make sure that some "reserved" objc + // names get renamed in a way so they don't conflict. // // This "test" confirms that the expected names are generated, // otherwise the test itself will fail to compile. diff --git a/php/BUILD.bazel b/php/BUILD.bazel index 1f31466eda..3c97ad8db2 100644 --- a/php/BUILD.bazel +++ b/php/BUILD.bazel @@ -3,6 +3,7 @@ # See also code generation logic under /src/google/protobuf/compiler/php. load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix") +load("@upb//cmake:build_defs.bzl", "staleness_test") load("//build_defs:internal_shell.bzl", "inline_sh_binary") load("//conformance:defs.bzl", "conformance_test") @@ -84,6 +85,29 @@ conformance_test( }), ) +genrule( + name = "copy_php_amalgamation_h", + srcs = ["@upb//:php-upb.h"], + outs = ["generated-in/ext/google/protobuf/php-upb.h"], + cmd = "cp $< $@", +) + +genrule( + name = "copy_php_amalgamation_c", + srcs = ["@upb//:php-upb.c"], + outs = ["generated-in/ext/google/protobuf/php-upb.c"], + cmd = "cp $< $@", +) + +staleness_test( + name = "test_amalgamation_staleness", + outs = [ + "ext/google/protobuf/php-upb.h", + "ext/google/protobuf/php-upb.c", + ], + generated_pattern = "generated-in/%s", +) + ################################################################################ # Distribution files ################################################################################ diff --git a/php/ext/google/protobuf/message.c b/php/ext/google/protobuf/message.c index 83c51a4941..0c90705eaf 100644 --- a/php/ext/google/protobuf/message.c +++ b/php/ext/google/protobuf/message.c @@ -646,6 +646,25 @@ PHP_METHOD(Message, clear) { upb_Message_Clear(intern->msg, intern->desc->msgdef); } +static bool Message_checkEncodeStatus(upb_EncodeStatus status) { + switch (status) { + case kUpb_EncodeStatus_Ok: + return true; + case kUpb_EncodeStatus_OutOfMemory: + zend_throw_exception_ex(NULL, 0, "Out of memory"); + return false; + case kUpb_EncodeStatus_MaxDepthExceeded: + zend_throw_exception_ex(NULL, 0, "Max nesting exceeded"); + return false; + case kUpb_EncodeStatus_MissingRequired: + zend_throw_exception_ex(NULL, 0, "Missing required field"); + return false; + default: + zend_throw_exception_ex(NULL, 0, "Unknown error encoding"); + return false; + } +} + /** * Message::mergeFrom() * @@ -673,14 +692,9 @@ PHP_METHOD(Message, mergeFrom) { // zend_parse_parameters(). PBPHP_ASSERT(from->desc == intern->desc); - // TODO(haberman): use a temp arena for this once we can make upb_decode() - // copy strings. - pb = upb_Encode(from->msg, l, 0, arena, &size); - - if (!pb) { - zend_throw_exception_ex(NULL, 0, "Max nesting exceeded"); - return; - } + // TODO(haberman): use a temp arena for this. + upb_EncodeStatus status = upb_Encode(from->msg, l, 0, arena, &pb, &size); + if (!Message_checkEncodeStatus(status)) return; ok = upb_Decode(pb, size, intern->msg, l, NULL, 0, arena) == kUpb_DecodeStatus_Ok; @@ -730,7 +744,9 @@ PHP_METHOD(Message, serializeToString) { char *data; size_t size; - data = upb_Encode(intern->msg, l, 0, tmp_arena, &size); + upb_EncodeStatus status = + upb_Encode(intern->msg, l, 0, tmp_arena, &data, &size); + if (!Message_checkEncodeStatus(status)) return; if (!data) { zend_throw_exception_ex(NULL, 0, "Error occurred during serialization"); @@ -1232,8 +1248,12 @@ PHP_METHOD(google_protobuf_Any, pack) { msg = (Message*)Z_OBJ_P(val); // Serialize and set value. - value.data = upb_Encode(msg->msg, upb_MessageDef_MiniTable(msg->desc->msgdef), - 0, arena, &value.size); + char* pb; + upb_EncodeStatus status = + upb_Encode(msg->msg, upb_MessageDef_MiniTable(msg->desc->msgdef), 0, + arena, &pb, &value.size); + if (!Message_checkEncodeStatus(status)) return; + value.data = pb; Message_setval(intern, "value", StringVal(value)); // Set type url: type_url_prefix + fully_qualified_name diff --git a/php/ext/google/protobuf/package.xml b/php/ext/google/protobuf/package.xml index 4f0b8b4277..3a9f4250d9 100644 --- a/php/ext/google/protobuf/package.xml +++ b/php/ext/google/protobuf/package.xml @@ -10,11 +10,11 @@ protobuf-packages@google.com yes - 2022-09-13 - + 2022-09-29 + - 3.21.6 - 3.21.6 + 3.21.7 + 3.21.7 stable @@ -43,6 +43,7 @@ + @@ -1418,5 +1419,20 @@ G A release. + + + 3.21.7 + 3.21.7 + + + stable + stable + + 2022-09-29 + + BSD-3-Clause + + + diff --git a/php/ext/google/protobuf/php-upb.c b/php/ext/google/protobuf/php-upb.c index 1179ac3999..0116c2737f 100644 --- a/php/ext/google/protobuf/php-upb.c +++ b/php/ext/google/protobuf/php-upb.c @@ -1,31 +1,5 @@ /* Amalgamated source file */ #include "php-upb.h" -/* - * Copyright (c) 2009-2021, Google LLC - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Google LLC nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ /* * This is where we define macros used across upb. @@ -56,8 +30,20 @@ #error upb requires C99 or C++11 or MSVC >= 2015. #endif -#include +// Portable check for GCC minimum version: +// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +#define UPB_GNUC_MIN(x, y) \ + (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y)) +#else +#define UPB_GNUC_MIN(x, y) 0 +#endif + +#include +#include +#include #include +#include #if UINTPTR_MAX == 0xffffffff #define UPB_SIZE(size32, size64) size32 @@ -90,9 +76,10 @@ #define UPB_INLINE static #endif +#define UPB_MALLOC_ALIGN 8 #define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align)) #define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align)) -#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, 16) +#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, UPB_MALLOC_ALIGN) #define UPB_ALIGN_OF(type) offsetof (struct { char c; type member; }, member) /* Hints to the compiler about likely/unlikely branches. */ @@ -230,7 +217,11 @@ #undef UPB_FASTTABLE_SUPPORTED -/* ASAN poisoning (for arena) *************************************************/ +/* ASAN poisoning (for arena). + * If using UPB from an interpreted language like Ruby, a build of the + * interpreter compiled with ASAN enabled must be used in order to get sane and + * expected behavior. + */ #if defined(__SANITIZE_ADDRESS__) #define UPB_ASAN 1 @@ -254,6107 +245,7735 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); ((void)(addr), (void)(size)) #endif -/** upb/decode.c ************************************************************/ +/* Disable proto2 arena behavior (TEMPORARY) **********************************/ -#include -#include +#ifdef UPB_DISABLE_PROTO2_ENUM_CHECKING +#define UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 1 +#else +#define UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 0 +#endif +#if defined(__cplusplus) +#if defined(__clang__) || UPB_GNUC_MIN(6, 0) +// https://gcc.gnu.org/gcc-6/changes.html +#if __cplusplus >= 201402L +#define UPB_DEPRECATED [[deprecated]] +#else +#define UPB_DEPRECATED __attribute__((deprecated)) +#endif +#else +#define UPB_DEPRECATED +#endif +#else +#define UPB_DEPRECATED +#endif -/* Must be last. */ - -/* Maps descriptor type -> elem_size_lg2. */ -static const uint8_t desctype_to_elem_size_lg2[] = { - -1, /* invalid descriptor type */ - 3, /* DOUBLE */ - 2, /* FLOAT */ - 3, /* INT64 */ - 3, /* UINT64 */ - 2, /* INT32 */ - 3, /* FIXED64 */ - 2, /* FIXED32 */ - 0, /* BOOL */ - UPB_SIZE(3, 4), /* STRING */ - UPB_SIZE(2, 3), /* GROUP */ - UPB_SIZE(2, 3), /* MESSAGE */ - UPB_SIZE(3, 4), /* BYTES */ - 2, /* UINT32 */ - 2, /* ENUM */ - 2, /* SFIXED32 */ - 3, /* SFIXED64 */ - 2, /* SINT32 */ - 3, /* SINT64 */ -}; -/* Maps descriptor type -> upb map size. */ -static const uint8_t desctype_to_mapsize[] = { - -1, /* invalid descriptor type */ - 8, /* DOUBLE */ - 4, /* FLOAT */ - 8, /* INT64 */ - 8, /* UINT64 */ - 4, /* INT32 */ - 8, /* FIXED64 */ - 4, /* FIXED32 */ - 1, /* BOOL */ - UPB_MAPTYPE_STRING, /* STRING */ - sizeof(void*), /* GROUP */ - sizeof(void*), /* MESSAGE */ - UPB_MAPTYPE_STRING, /* BYTES */ - 4, /* UINT32 */ - 4, /* ENUM */ - 4, /* SFIXED32 */ - 8, /* SFIXED64 */ - 4, /* SINT32 */ - 8, /* SINT64 */ -}; +#include -static const unsigned FIXED32_OK_MASK = (1 << kUpb_FieldType_Float) | - (1 << kUpb_FieldType_Fixed32) | - (1 << kUpb_FieldType_SFixed32); - -static const unsigned FIXED64_OK_MASK = (1 << kUpb_FieldType_Double) | - (1 << kUpb_FieldType_Fixed64) | - (1 << kUpb_FieldType_SFixed64); - -/* Three fake field types for MessageSet. */ -#define TYPE_MSGSET_ITEM 19 -#define TYPE_MSGSET_TYPE_ID 20 -#define TYPE_COUNT 20 - -/* Op: an action to be performed for a wire-type/field-type combination. */ -#define OP_UNKNOWN -1 /* Unknown field. */ -#define OP_MSGSET_ITEM -2 -#define OP_MSGSET_TYPEID -3 -#define OP_SCALAR_LG2(n) (n) /* n in [0, 2, 3] => op in [0, 2, 3] */ -#define OP_ENUM 1 -#define OP_STRING 4 -#define OP_BYTES 5 -#define OP_SUBMSG 6 -/* Scalar fields use only ops above. Repeated fields can use any op. */ -#define OP_FIXPCK_LG2(n) (n + 5) /* n in [2, 3] => op in [7, 8] */ -#define OP_VARPCK_LG2(n) (n + 9) /* n in [0, 2, 3] => op in [9, 11, 12] */ -#define OP_PACKED_ENUM 13 - -static const int8_t varint_ops[] = { - OP_UNKNOWN, /* field not found */ - OP_UNKNOWN, /* DOUBLE */ - OP_UNKNOWN, /* FLOAT */ - OP_SCALAR_LG2(3), /* INT64 */ - OP_SCALAR_LG2(3), /* UINT64 */ - OP_SCALAR_LG2(2), /* INT32 */ - OP_UNKNOWN, /* FIXED64 */ - OP_UNKNOWN, /* FIXED32 */ - OP_SCALAR_LG2(0), /* BOOL */ - OP_UNKNOWN, /* STRING */ - OP_UNKNOWN, /* GROUP */ - OP_UNKNOWN, /* MESSAGE */ - OP_UNKNOWN, /* BYTES */ - OP_SCALAR_LG2(2), /* UINT32 */ - OP_ENUM, /* ENUM */ - OP_UNKNOWN, /* SFIXED32 */ - OP_UNKNOWN, /* SFIXED64 */ - OP_SCALAR_LG2(2), /* SINT32 */ - OP_SCALAR_LG2(3), /* SINT64 */ - OP_UNKNOWN, /* MSGSET_ITEM */ - OP_MSGSET_TYPEID, /* MSGSET TYPEID */ -}; +// Must be last. -static const int8_t delim_ops[] = { - /* For non-repeated field type. */ - OP_UNKNOWN, /* field not found */ - OP_UNKNOWN, /* DOUBLE */ - OP_UNKNOWN, /* FLOAT */ - OP_UNKNOWN, /* INT64 */ - OP_UNKNOWN, /* UINT64 */ - OP_UNKNOWN, /* INT32 */ - OP_UNKNOWN, /* FIXED64 */ - OP_UNKNOWN, /* FIXED32 */ - OP_UNKNOWN, /* BOOL */ - OP_STRING, /* STRING */ - OP_UNKNOWN, /* GROUP */ - OP_SUBMSG, /* MESSAGE */ - OP_BYTES, /* BYTES */ - OP_UNKNOWN, /* UINT32 */ - OP_UNKNOWN, /* ENUM */ - OP_UNKNOWN, /* SFIXED32 */ - OP_UNKNOWN, /* SFIXED64 */ - OP_UNKNOWN, /* SINT32 */ - OP_UNKNOWN, /* SINT64 */ - OP_UNKNOWN, /* MSGSET_ITEM */ - OP_UNKNOWN, /* MSGSET TYPEID */ - /* For repeated field type. */ - OP_FIXPCK_LG2(3), /* REPEATED DOUBLE */ - OP_FIXPCK_LG2(2), /* REPEATED FLOAT */ - OP_VARPCK_LG2(3), /* REPEATED INT64 */ - OP_VARPCK_LG2(3), /* REPEATED UINT64 */ - OP_VARPCK_LG2(2), /* REPEATED INT32 */ - OP_FIXPCK_LG2(3), /* REPEATED FIXED64 */ - OP_FIXPCK_LG2(2), /* REPEATED FIXED32 */ - OP_VARPCK_LG2(0), /* REPEATED BOOL */ - OP_STRING, /* REPEATED STRING */ - OP_SUBMSG, /* REPEATED GROUP */ - OP_SUBMSG, /* REPEATED MESSAGE */ - OP_BYTES, /* REPEATED BYTES */ - OP_VARPCK_LG2(2), /* REPEATED UINT32 */ - OP_PACKED_ENUM, /* REPEATED ENUM */ - OP_FIXPCK_LG2(2), /* REPEATED SFIXED32 */ - OP_FIXPCK_LG2(3), /* REPEATED SFIXED64 */ - OP_VARPCK_LG2(2), /* REPEATED SINT32 */ - OP_VARPCK_LG2(3), /* REPEATED SINT64 */ - /* Omitting MSGSET_*, because we never emit a repeated msgset type */ -}; +bool _upb_array_realloc(upb_Array* arr, size_t min_capacity, upb_Arena* arena) { + size_t new_capacity = UPB_MAX(arr->capacity, 4); + int elem_size_lg2 = arr->data & 7; + size_t old_bytes = arr->capacity << elem_size_lg2; + size_t new_bytes; + void* ptr = _upb_array_ptr(arr); -typedef union { - bool bool_val; - uint32_t uint32_val; - uint64_t uint64_val; - uint32_t size; -} wireval; + /* Log2 ceiling of size. */ + while (new_capacity < min_capacity) new_capacity *= 2; -static const char* decode_msg(upb_Decoder* d, const char* ptr, upb_Message* msg, - const upb_MiniTable* layout); + new_bytes = new_capacity << elem_size_lg2; + ptr = upb_Arena_Realloc(arena, ptr, old_bytes, new_bytes); -UPB_NORETURN static void* decode_err(upb_Decoder* d, upb_DecodeStatus status) { - assert(status != kUpb_DecodeStatus_Ok); - UPB_LONGJMP(d->err, status); -} + if (!ptr) { + return false; + } -const char* fastdecode_err(upb_Decoder* d, int status) { - assert(status != kUpb_DecodeStatus_Ok); - UPB_LONGJMP(d->err, status); - return NULL; -} -static void decode_verifyutf8(upb_Decoder* d, const char* buf, int len) { - if (!decode_verifyutf8_inl(buf, len)) - decode_err(d, kUpb_DecodeStatus_BadUtf8); + arr->data = _upb_tag_arrptr(ptr, elem_size_lg2); + arr->capacity = new_capacity; + return true; } -static bool decode_reserve(upb_Decoder* d, upb_Array* arr, size_t elem) { - bool need_realloc = arr->size - arr->len < elem; - if (need_realloc && !_upb_array_realloc(arr, arr->len + elem, &d->arena)) { - decode_err(d, kUpb_DecodeStatus_OutOfMemory); +static upb_Array* getorcreate_array(upb_Array** arr_ptr, int elem_size_lg2, + upb_Arena* arena) { + upb_Array* arr = *arr_ptr; + if (!arr) { + arr = _upb_Array_New(arena, 4, elem_size_lg2); + if (!arr) return NULL; + *arr_ptr = arr; } - return need_realloc; + return arr; } -typedef struct { - const char* ptr; - uint64_t val; -} decode_vret; - -UPB_NOINLINE -static decode_vret decode_longvarint64(const char* ptr, uint64_t val) { - decode_vret ret = {NULL, 0}; - uint64_t byte; - int i; - for (i = 1; i < 10; i++) { - byte = (uint8_t)ptr[i]; - val += (byte - 1) << (i * 7); - if (!(byte & 0x80)) { - ret.ptr = ptr + i + 1; - ret.val = val; - return ret; - } - } - return ret; +void* _upb_Array_Resize_fallback(upb_Array** arr_ptr, size_t size, + int elem_size_lg2, upb_Arena* arena) { + upb_Array* arr = getorcreate_array(arr_ptr, elem_size_lg2, arena); + return arr && _upb_Array_Resize(arr, size, arena) ? _upb_array_ptr(arr) + : NULL; } -UPB_FORCEINLINE -static const char* decode_varint64(upb_Decoder* d, const char* ptr, - uint64_t* val) { - uint64_t byte = (uint8_t)*ptr; - if (UPB_LIKELY((byte & 0x80) == 0)) { - *val = byte; - return ptr + 1; - } else { - decode_vret res = decode_longvarint64(ptr, byte); - if (!res.ptr) return decode_err(d, kUpb_DecodeStatus_Malformed); - *val = res.val; - return res.ptr; - } -} +bool _upb_Array_Append_fallback(upb_Array** arr_ptr, const void* value, + int elem_size_lg2, upb_Arena* arena) { + upb_Array* arr = getorcreate_array(arr_ptr, elem_size_lg2, arena); + if (!arr) return false; -UPB_FORCEINLINE -static const char* decode_tag(upb_Decoder* d, const char* ptr, uint32_t* val) { - uint64_t byte = (uint8_t)*ptr; - if (UPB_LIKELY((byte & 0x80) == 0)) { - *val = byte; - return ptr + 1; - } else { - const char* start = ptr; - decode_vret res = decode_longvarint64(ptr, byte); - if (!res.ptr || res.ptr - start > 5 || res.val > UINT32_MAX) { - return decode_err(d, kUpb_DecodeStatus_Malformed); - } - *val = res.val; - return res.ptr; - } -} + size_t elems = arr->size; -static void decode_munge_int32(wireval* val) { - if (!_upb_IsLittleEndian()) { - /* The next stage will memcpy(dst, &val, 4) */ - val->uint32_val = val->uint64_val; + if (!_upb_Array_Resize(arr, elems + 1, arena)) { + return false; } + + char* data = _upb_array_ptr(arr); + memcpy(data + (elems << elem_size_lg2), value, 1 << elem_size_lg2); + return true; } -static void decode_munge(int type, wireval* val) { - switch (type) { - case kUpb_FieldType_Bool: - val->bool_val = val->uint64_val != 0; - break; - case kUpb_FieldType_SInt32: { - uint32_t n = val->uint64_val; - val->uint32_val = (n >> 1) ^ -(int32_t)(n & 1); - break; - } - case kUpb_FieldType_SInt64: { - uint64_t n = val->uint64_val; - val->uint64_val = (n >> 1) ^ -(int64_t)(n & 1); - break; + +// Must be last. + +const char* upb_BufToUint64(const char* ptr, const char* end, uint64_t* val) { + uint64_t u64 = 0; + while (ptr < end) { + unsigned ch = *ptr - '0'; + if (ch >= 10) break; + if (u64 > UINT64_MAX / 10 || u64 * 10 > UINT64_MAX - ch) { + return NULL; // integer overflow } - case kUpb_FieldType_Int32: - case kUpb_FieldType_UInt32: - case kUpb_FieldType_Enum: - decode_munge_int32(val); - break; + u64 *= 10; + u64 += ch; + ptr++; } -} -static upb_Message* decode_newsubmsg(upb_Decoder* d, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field) { - const upb_MiniTable* subl = subs[field->submsg_index].submsg; - return _upb_Message_New_inl(subl, &d->arena); + *val = u64; + return ptr; } -UPB_NOINLINE -const char* decode_isdonefallback(upb_Decoder* d, const char* ptr, - int overrun) { - int status; - ptr = decode_isdonefallback_inl(d, ptr, overrun, &status); - if (ptr == NULL) { - return decode_err(d, status); +const char* upb_BufToInt64(const char* ptr, const char* end, int64_t* val, + bool* is_neg) { + bool neg = false; + uint64_t u64; + + if (ptr != end && *ptr == '-') { + ptr++; + neg = true; } - return ptr; -} -static const char* decode_readstr(upb_Decoder* d, const char* ptr, int size, - upb_StringView* str) { - if (d->options & kUpb_DecodeOption_AliasString) { - str->data = ptr; - } else { - char* data = upb_Arena_Malloc(&d->arena, size); - if (!data) return decode_err(d, kUpb_DecodeStatus_OutOfMemory); - memcpy(data, ptr, size); - str->data = data; + ptr = upb_BufToUint64(ptr, end, &u64); + if (!ptr || u64 > (uint64_t)INT64_MAX + neg) { + return NULL; // integer overflow } - str->size = size; - return ptr + size; -} -UPB_FORCEINLINE -static const char* decode_tosubmsg2(upb_Decoder* d, const char* ptr, - upb_Message* submsg, - const upb_MiniTable* subl, int size) { - int saved_delta = decode_pushlimit(d, ptr, size); - if (--d->depth < 0) return decode_err(d, kUpb_DecodeStatus_MaxDepthExceeded); - ptr = decode_msg(d, ptr, submsg, subl); - if (d->end_group != DECODE_NOGROUP) - return decode_err(d, kUpb_DecodeStatus_Malformed); - decode_poplimit(d, ptr, saved_delta); - d->depth++; + *val = neg ? -u64 : u64; + if (is_neg) *is_neg = neg; return ptr; } -UPB_FORCEINLINE -static const char* decode_tosubmsg(upb_Decoder* d, const char* ptr, - upb_Message* submsg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, int size) { - return decode_tosubmsg2(d, ptr, submsg, subs[field->submsg_index].submsg, - size); -} -UPB_FORCEINLINE -static const char* decode_group(upb_Decoder* d, const char* ptr, - upb_Message* submsg, const upb_MiniTable* subl, - uint32_t number) { - if (--d->depth < 0) return decode_err(d, kUpb_DecodeStatus_MaxDepthExceeded); - if (decode_isdone(d, &ptr)) { - return decode_err(d, kUpb_DecodeStatus_Malformed); - } - ptr = decode_msg(d, ptr, submsg, subl); - if (d->end_group != number) return decode_err(d, kUpb_DecodeStatus_Malformed); - d->end_group = DECODE_NOGROUP; - d->depth++; - return ptr; -} +#include -UPB_FORCEINLINE -static const char* decode_togroup(upb_Decoder* d, const char* ptr, - upb_Message* submsg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field) { - const upb_MiniTable* subl = subs[field->submsg_index].submsg; - return decode_group(d, ptr, submsg, subl, field->number); -} -static char* encode_varint32(uint32_t val, char* ptr) { - do { - uint8_t byte = val & 0x7fU; - val >>= 7; - if (val) byte |= 0x80U; - *(ptr++) = byte; - } while (val); - return ptr; +// Must be last. + +/* Strings/bytes are special-cased in maps. */ +static char _upb_CTypeo_mapsize[12] = { + 0, + 1, /* kUpb_CType_Bool */ + 4, /* kUpb_CType_Float */ + 4, /* kUpb_CType_Int32 */ + 4, /* kUpb_CType_UInt32 */ + 4, /* kUpb_CType_Enum */ + sizeof(void*), /* kUpb_CType_Message */ + 8, /* kUpb_CType_Double */ + 8, /* kUpb_CType_Int64 */ + 8, /* kUpb_CType_UInt64 */ + 0, /* kUpb_CType_String */ + 0, /* kUpb_CType_Bytes */ +}; + +upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type) { + return _upb_Map_New(a, _upb_CTypeo_mapsize[key_type], + _upb_CTypeo_mapsize[value_type]); } -UPB_NOINLINE -static bool decode_checkenum_slow(upb_Decoder* d, const char* ptr, - upb_Message* msg, const upb_MiniTable_Enum* e, - const upb_MiniTable_Field* field, - uint32_t v) { - // OPT: binary search long lists? - int n = e->value_count; - for (int i = 0; i < n; i++) { - if ((uint32_t)e->values[i] == v) return true; - } +size_t upb_Map_Size(const upb_Map* map) { return _upb_Map_Size(map); } - // Unrecognized enum goes into unknown fields. - // For packed fields the tag could be arbitrarily far in the past, so we - // just re-encode the tag here. - char buf[20]; - char* end = buf; - uint32_t tag = ((uint32_t)field->number << 3) | kUpb_WireType_Varint; - end = encode_varint32(tag, end); - end = encode_varint32(v, end); +bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, + upb_MessageValue* val) { + return _upb_Map_Get(map, &key, map->key_size, val, map->val_size); +} - if (!_upb_Message_AddUnknown(msg, buf, end - buf, &d->arena)) { - decode_err(d, kUpb_DecodeStatus_OutOfMemory); - } +void upb_Map_Clear(upb_Map* map) { _upb_Map_Clear(map); } - return false; +upb_MapInsertStatus upb_Map_Insert(upb_Map* map, upb_MessageValue key, + upb_MessageValue val, upb_Arena* arena) { + return (upb_MapInsertStatus)_upb_Map_Insert(map, &key, map->key_size, &val, + map->val_size, arena); } -UPB_FORCEINLINE -static bool decode_checkenum(upb_Decoder* d, const char* ptr, upb_Message* msg, - const upb_MiniTable_Enum* e, - const upb_MiniTable_Field* field, wireval* val) { - uint32_t v = val->uint32_val; +bool upb_Map_Delete(upb_Map* map, upb_MessageValue key) { + return _upb_Map_Delete(map, &key, map->key_size); +} - if (UPB_LIKELY(v < 64) && UPB_LIKELY(((1ULL << v) & e->mask))) return true; +bool upb_MapIterator_Next(const upb_Map* map, size_t* iter) { + return _upb_map_next(map, iter); +} - return decode_checkenum_slow(d, ptr, msg, e, field, v); +bool upb_MapIterator_Done(const upb_Map* map, size_t iter) { + upb_strtable_iter i; + UPB_ASSERT(iter != kUpb_Map_Begin); + i.t = &map->table; + i.index = iter; + return upb_strtable_done(&i); } -UPB_NOINLINE -static const char* decode_enum_toarray(upb_Decoder* d, const char* ptr, - upb_Message* msg, upb_Array* arr, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, - wireval* val) { - const upb_MiniTable_Enum* e = subs[field->submsg_index].subenum; - if (!decode_checkenum(d, ptr, msg, e, field, val)) return ptr; - void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void); - arr->len++; - memcpy(mem, val, 4); - return ptr; +/* Returns the key and value for this entry of the map. */ +upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter) { + upb_strtable_iter i; + upb_MessageValue ret; + i.t = &map->table; + i.index = iter; + _upb_map_fromkey(upb_strtable_iter_key(&i), &ret, map->key_size); + return ret; } -UPB_FORCEINLINE -static const char* decode_fixed_packed(upb_Decoder* d, const char* ptr, - upb_Array* arr, wireval* val, - const upb_MiniTable_Field* field, - int lg2) { - int mask = (1 << lg2) - 1; - size_t count = val->size >> lg2; - if ((val->size & mask) != 0) { - // Length isn't a round multiple of elem size. - return decode_err(d, kUpb_DecodeStatus_Malformed); - } - decode_reserve(d, arr, count); - void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); - arr->len += count; - // Note: if/when the decoder supports multi-buffer input, we will need to - // handle buffer seams here. - if (_upb_IsLittleEndian()) { - memcpy(mem, ptr, val->size); - ptr += val->size; - } else { - const char* end = ptr + val->size; - char* dst = mem; - while (ptr < end) { - if (lg2 == 2) { - uint32_t val; - memcpy(&val, ptr, sizeof(val)); - val = _upb_BigEndian_Swap32(val); - memcpy(dst, &val, sizeof(val)); - } else { - UPB_ASSERT(lg2 == 3); - uint64_t val; - memcpy(&val, ptr, sizeof(val)); - val = _upb_BigEndian_Swap64(val); - memcpy(dst, &val, sizeof(val)); - } - ptr += 1 << lg2; - dst += 1 << lg2; - } - } - - return ptr; -} - -UPB_FORCEINLINE -static const char* decode_varint_packed(upb_Decoder* d, const char* ptr, - upb_Array* arr, wireval* val, - const upb_MiniTable_Field* field, - int lg2) { - int scale = 1 << lg2; - int saved_limit = decode_pushlimit(d, ptr, val->size); - char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); - while (!decode_isdone(d, &ptr)) { - wireval elem; - ptr = decode_varint64(d, ptr, &elem.uint64_val); - decode_munge(field->descriptortype, &elem); - if (decode_reserve(d, arr, 1)) { - out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); - } - arr->len++; - memcpy(out, &elem, scale); - out += scale; - } - decode_poplimit(d, ptr, saved_limit); - return ptr; +upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter) { + upb_strtable_iter i; + upb_MessageValue ret; + i.t = &map->table; + i.index = iter; + _upb_map_fromvalue(upb_strtable_iter_value(&i), &ret, map->val_size); + return ret; } -UPB_NOINLINE -static const char* decode_enum_packed(upb_Decoder* d, const char* ptr, - upb_Message* msg, upb_Array* arr, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, - wireval* val) { - const upb_MiniTable_Enum* e = subs[field->submsg_index].subenum; - int saved_limit = decode_pushlimit(d, ptr, val->size); - char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void); - while (!decode_isdone(d, &ptr)) { - wireval elem; - ptr = decode_varint64(d, ptr, &elem.uint64_val); - decode_munge_int32(&elem); - if (!decode_checkenum(d, ptr, msg, e, field, &elem)) { - continue; - } - if (decode_reserve(d, arr, 1)) { - out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void); - } - arr->len++; - memcpy(out, &elem, 4); - out += 4; - } - decode_poplimit(d, ptr, saved_limit); - return ptr; -} +/* void upb_MapIterator_SetValue(upb_Map *map, size_t iter, upb_MessageValue + * value); */ +/* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/descriptor.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ -static const char* decode_toarray(upb_Decoder* d, const char* ptr, - upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, - wireval* val, int op) { - upb_Array** arrp = UPB_PTR_AT(msg, field->offset, void); - upb_Array* arr = *arrp; - void* mem; +#include - if (arr) { - decode_reserve(d, arr, 1); - } else { - size_t lg2 = desctype_to_elem_size_lg2[field->descriptortype]; - arr = _upb_Array_New(&d->arena, 4, lg2); - if (!arr) return decode_err(d, kUpb_DecodeStatus_OutOfMemory); - *arrp = arr; - } - switch (op) { - case OP_SCALAR_LG2(0): - case OP_SCALAR_LG2(2): - case OP_SCALAR_LG2(3): - /* Append scalar value. */ - mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << op, void); - arr->len++; - memcpy(mem, val, 1 << op); - return ptr; - case OP_STRING: - decode_verifyutf8(d, ptr, val->size); - /* Fallthrough. */ - case OP_BYTES: { - /* Append bytes. */ - upb_StringView* str = (upb_StringView*)_upb_array_ptr(arr) + arr->len; - arr->len++; - return decode_readstr(d, ptr, val->size, str); - } - case OP_SUBMSG: { - /* Append submessage / group. */ - upb_Message* submsg = decode_newsubmsg(d, subs, field); - *UPB_PTR_AT(_upb_array_ptr(arr), arr->len * sizeof(void*), upb_Message*) = - submsg; - arr->len++; - if (UPB_UNLIKELY(field->descriptortype == kUpb_FieldType_Group)) { - return decode_togroup(d, ptr, submsg, subs, field); - } else { - return decode_tosubmsg(d, ptr, submsg, subs, field, val->size); - } - } - case OP_FIXPCK_LG2(2): - case OP_FIXPCK_LG2(3): - return decode_fixed_packed(d, ptr, arr, val, field, - op - OP_FIXPCK_LG2(0)); - case OP_VARPCK_LG2(0): - case OP_VARPCK_LG2(2): - case OP_VARPCK_LG2(3): - return decode_varint_packed(d, ptr, arr, val, field, - op - OP_VARPCK_LG2(0)); - case OP_ENUM: - return decode_enum_toarray(d, ptr, msg, arr, subs, field, val); - case OP_PACKED_ENUM: - return decode_enum_packed(d, ptr, msg, arr, subs, field, val); - default: - UPB_UNREACHABLE(); - } -} +static const upb_MiniTable_Sub google_protobuf_FileDescriptorSet_submsgs[1] = { + {.submsg = &google_protobuf_FileDescriptorProto_msg_init}, +}; -static const char* decode_tomap(upb_Decoder* d, const char* ptr, - upb_Message* msg, const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, - wireval* val) { - upb_Map** map_p = UPB_PTR_AT(msg, field->offset, upb_Map*); - upb_Map* map = *map_p; - upb_MapEntry ent; - const upb_MiniTable* entry = subs[field->submsg_index].submsg; +static const upb_MiniTable_Field google_protobuf_FileDescriptorSet__fields[1] = { + {1, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - if (!map) { - /* Lazily create map. */ - const upb_MiniTable_Field* key_field = &entry->fields[0]; - const upb_MiniTable_Field* val_field = &entry->fields[1]; - char key_size = desctype_to_mapsize[key_field->descriptortype]; - char val_size = desctype_to_mapsize[val_field->descriptortype]; - UPB_ASSERT(key_field->offset == 0); - UPB_ASSERT(val_field->offset == sizeof(upb_StringView)); - map = _upb_Map_New(&d->arena, key_size, val_size); - *map_p = map; - } +const upb_MiniTable google_protobuf_FileDescriptorSet_msg_init = { + &google_protobuf_FileDescriptorSet_submsgs[0], + &google_protobuf_FileDescriptorSet__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, +}; - /* Parse map entry. */ - memset(&ent, 0, sizeof(ent)); +static const upb_MiniTable_Sub google_protobuf_FileDescriptorProto_submsgs[6] = { + {.submsg = &google_protobuf_DescriptorProto_msg_init}, + {.submsg = &google_protobuf_EnumDescriptorProto_msg_init}, + {.submsg = &google_protobuf_ServiceDescriptorProto_msg_init}, + {.submsg = &google_protobuf_FieldDescriptorProto_msg_init}, + {.submsg = &google_protobuf_FileOptions_msg_init}, + {.submsg = &google_protobuf_SourceCodeInfo_msg_init}, +}; - if (entry->fields[1].descriptortype == kUpb_FieldType_Message || - entry->fields[1].descriptortype == kUpb_FieldType_Group) { - /* Create proactively to handle the case where it doesn't appear. */ - ent.v.val = - upb_value_ptr(_upb_Message_New(entry->subs[0].submsg, &d->arena)); - } +static const upb_MiniTable_Field google_protobuf_FileDescriptorProto__fields[13] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(20, 40), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(24, 48), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(28, 56), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(32, 64), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(36, 72), UPB_SIZE(0, 0), 3, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(40, 80), UPB_SIZE(3, 3), 4, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(44, 88), UPB_SIZE(4, 4), 5, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(48, 96), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {11, UPB_SIZE(52, 104), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {12, UPB_SIZE(56, 112), UPB_SIZE(5, 5), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {13, UPB_SIZE(64, 128), UPB_SIZE(6, 6), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, +}; - ptr = decode_tosubmsg(d, ptr, &ent.k, subs, field, val->size); - _upb_Map_Set(map, &ent.k, map->key_size, &ent.v, map->val_size, &d->arena); - return ptr; -} +const upb_MiniTable google_protobuf_FileDescriptorProto_msg_init = { + &google_protobuf_FileDescriptorProto_submsgs[0], + &google_protobuf_FileDescriptorProto__fields[0], + UPB_SIZE(72, 144), 13, kUpb_ExtMode_NonExtendable, 13, 255, 0, +}; -static const char* decode_tomsg(upb_Decoder* d, const char* ptr, - upb_Message* msg, const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, wireval* val, - int op) { - void* mem = UPB_PTR_AT(msg, field->offset, void); - int type = field->descriptortype; +static const upb_MiniTable_Sub google_protobuf_DescriptorProto_submsgs[8] = { + {.submsg = &google_protobuf_FieldDescriptorProto_msg_init}, + {.submsg = &google_protobuf_DescriptorProto_msg_init}, + {.submsg = &google_protobuf_EnumDescriptorProto_msg_init}, + {.submsg = &google_protobuf_DescriptorProto_ExtensionRange_msg_init}, + {.submsg = &google_protobuf_FieldDescriptorProto_msg_init}, + {.submsg = &google_protobuf_MessageOptions_msg_init}, + {.submsg = &google_protobuf_OneofDescriptorProto_msg_init}, + {.submsg = &google_protobuf_DescriptorProto_ReservedRange_msg_init}, +}; - if (UPB_UNLIKELY(op == OP_ENUM) && - !decode_checkenum(d, ptr, msg, subs[field->submsg_index].subenum, field, - val)) { - return ptr; - } +static const upb_MiniTable_Field google_protobuf_DescriptorProto__fields[10] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 32), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 40), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(24, 48), UPB_SIZE(0, 0), 3, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(28, 56), UPB_SIZE(0, 0), 4, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(32, 64), UPB_SIZE(2, 2), 5, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(36, 72), UPB_SIZE(0, 0), 6, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(40, 80), UPB_SIZE(0, 0), 7, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(44, 88), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - /* Set presence if necessary. */ - if (field->presence > 0) { - _upb_sethas_field(msg, field); - } else if (field->presence < 0) { - /* Oneof case */ - uint32_t* oneof_case = _upb_oneofcase_field(msg, field); - if (op == OP_SUBMSG && *oneof_case != field->number) { - memset(mem, 0, sizeof(void*)); - } - *oneof_case = field->number; - } +const upb_MiniTable google_protobuf_DescriptorProto_msg_init = { + &google_protobuf_DescriptorProto_submsgs[0], + &google_protobuf_DescriptorProto__fields[0], + UPB_SIZE(48, 96), 10, kUpb_ExtMode_NonExtendable, 10, 255, 0, +}; - /* Store into message. */ - switch (op) { - case OP_SUBMSG: { - upb_Message** submsgp = mem; - upb_Message* submsg = *submsgp; - if (!submsg) { - submsg = decode_newsubmsg(d, subs, field); - *submsgp = submsg; - } - if (UPB_UNLIKELY(type == kUpb_FieldType_Group)) { - ptr = decode_togroup(d, ptr, submsg, subs, field); - } else { - ptr = decode_tosubmsg(d, ptr, submsg, subs, field, val->size); - } - break; - } - case OP_STRING: - decode_verifyutf8(d, ptr, val->size); - /* Fallthrough. */ - case OP_BYTES: - return decode_readstr(d, ptr, val->size, mem); - case OP_SCALAR_LG2(3): - memcpy(mem, val, 8); - break; - case OP_ENUM: - case OP_SCALAR_LG2(2): - memcpy(mem, val, 4); - break; - case OP_SCALAR_LG2(0): - memcpy(mem, val, 1); - break; - default: - UPB_UNREACHABLE(); - } +static const upb_MiniTable_Sub google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = { + {.submsg = &google_protobuf_ExtensionRangeOptions_msg_init}, +}; - return ptr; -} +static const upb_MiniTable_Field google_protobuf_DescriptorProto_ExtensionRange__fields[3] = { + {1, UPB_SIZE(4, 4), UPB_SIZE(1, 1), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 8), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(12, 16), UPB_SIZE(3, 3), 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -UPB_NOINLINE -const char* decode_checkrequired(upb_Decoder* d, const char* ptr, - const upb_Message* msg, - const upb_MiniTable* l) { - assert(l->required_count); - if (UPB_LIKELY((d->options & kUpb_DecodeOption_CheckRequired) == 0)) { - return ptr; - } - uint64_t msg_head; - memcpy(&msg_head, msg, 8); - msg_head = _upb_BigEndian_Swap64(msg_head); - if (upb_MiniTable_requiredmask(l) & ~msg_head) { - d->missing_required = true; - } - return ptr; -} +const upb_MiniTable google_protobuf_DescriptorProto_ExtensionRange_msg_init = { + &google_protobuf_DescriptorProto_ExtensionRange_submsgs[0], + &google_protobuf_DescriptorProto_ExtensionRange__fields[0], + UPB_SIZE(16, 24), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, +}; -UPB_FORCEINLINE -static bool decode_tryfastdispatch(upb_Decoder* d, const char** ptr, - upb_Message* msg, - const upb_MiniTable* layout) { -#if UPB_FASTTABLE - if (layout && layout->table_mask != (unsigned char)-1) { - uint16_t tag = fastdecode_loadtag(*ptr); - intptr_t table = decode_totable(layout); - *ptr = fastdecode_tagdispatch(d, *ptr, msg, table, 0, tag); - return true; - } -#endif - return false; -} +static const upb_MiniTable_Field google_protobuf_DescriptorProto_ReservedRange__fields[2] = { + {1, UPB_SIZE(4, 4), UPB_SIZE(1, 1), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 8), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; -static const char* decode_msgset(upb_Decoder* d, const char* ptr, - upb_Message* msg, - const upb_MiniTable* layout) { - // We create a temporary upb_MiniTable here and abuse its fields as temporary - // storage, to avoid creating lots of MessageSet-specific parsing code-paths: - // 1. We store 'layout' in item_layout.subs. We will need this later as - // a key to look up extensions for this MessageSet. - // 2. We use item_layout.fields as temporary storage to store the extension - // we - // found when parsing the type id. - upb_MiniTable item_layout = { - .subs = (const upb_MiniTable_Sub[]){{.submsg = layout}}, - .fields = NULL, - .size = 0, - .field_count = 0, - .ext = upb_ExtMode_IsMessageSet_ITEM, - .dense_below = 0, - .table_mask = -1}; - return decode_group(d, ptr, msg, &item_layout, 1); -} - -static const upb_MiniTable_Field* decode_findfield(upb_Decoder* d, - const upb_MiniTable* l, - uint32_t field_number, - int* last_field_index) { - static upb_MiniTable_Field none = {0, 0, 0, 0, 0, 0}; - if (l == NULL) return &none; +const upb_MiniTable google_protobuf_DescriptorProto_ReservedRange_msg_init = { + NULL, + &google_protobuf_DescriptorProto_ReservedRange__fields[0], + UPB_SIZE(16, 16), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, +}; - size_t idx = ((size_t)field_number) - 1; // 0 wraps to SIZE_MAX - if (idx < l->dense_below) { - /* Fastest case: index into dense fields. */ - goto found; - } +static const upb_MiniTable_Sub google_protobuf_ExtensionRangeOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msg_init}, +}; - if (l->dense_below < l->field_count) { - /* Linear search non-dense fields. Resume scanning from last_field_index - * since fields are usually in order. */ - int last = *last_field_index; - for (idx = last; idx < l->field_count; idx++) { - if (l->fields[idx].number == field_number) { - goto found; - } - } +static const upb_MiniTable_Field google_protobuf_ExtensionRangeOptions__fields[1] = { + {999, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - for (idx = l->dense_below; idx < last; idx++) { - if (l->fields[idx].number == field_number) { - goto found; - } - } - } +const upb_MiniTable google_protobuf_ExtensionRangeOptions_msg_init = { + &google_protobuf_ExtensionRangeOptions_submsgs[0], + &google_protobuf_ExtensionRangeOptions__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_Extendable, 0, 255, 0, +}; - if (d->extreg) { - switch (l->ext) { - case upb_ExtMode_Extendable: { - const upb_MiniTable_Extension* ext = - _upb_extreg_get(d->extreg, l, field_number); - if (ext) return &ext->field; - break; - } - case upb_ExtMode_IsMessageSet: - if (field_number == _UPB_MSGSET_ITEM) { - static upb_MiniTable_Field item = {0, 0, 0, 0, TYPE_MSGSET_ITEM, 0}; - return &item; - } - break; - case upb_ExtMode_IsMessageSet_ITEM: - switch (field_number) { - case _UPB_MSGSET_TYPEID: { - static upb_MiniTable_Field type_id = { - 0, 0, 0, 0, TYPE_MSGSET_TYPE_ID, 0}; - return &type_id; - } - case _UPB_MSGSET_MESSAGE: - if (l->fields) { - // We saw type_id previously and succeeded in looking up msg. - return l->fields; - } else { - // TODO: out of order MessageSet. - // This is a very rare case: all serializers will emit in-order - // MessageSets. To hit this case there has to be some kind of - // re-ordering proxy. We should eventually handle this case, but - // not today. - } - break; - } - } - } +static const upb_MiniTable_Sub google_protobuf_FieldDescriptorProto_submsgs[3] = { + {.subenum = &google_protobuf_FieldDescriptorProto_Label_enum_init}, + {.subenum = &google_protobuf_FieldDescriptorProto_Type_enum_init}, + {.submsg = &google_protobuf_FieldOptions_msg_init}, +}; - return &none; /* Unknown field. */ +static const upb_MiniTable_Field google_protobuf_FieldDescriptorProto__fields[11] = { + {1, UPB_SIZE(24, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(32, 40), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(4, 4), UPB_SIZE(3, 3), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(8, 8), UPB_SIZE(4, 4), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(12, 12), UPB_SIZE(5, 5), 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(40, 56), UPB_SIZE(6, 6), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(48, 72), UPB_SIZE(7, 7), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(56, 88), UPB_SIZE(8, 8), 2, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(16, 16), UPB_SIZE(9, 9), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(60, 96), UPB_SIZE(10, 10), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {17, UPB_SIZE(20, 20), UPB_SIZE(11, 11), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +}; -found: - UPB_ASSERT(l->fields[idx].number == field_number); - *last_field_index = idx; - return &l->fields[idx]; -} - -UPB_FORCEINLINE -static const char* decode_wireval(upb_Decoder* d, const char* ptr, - const upb_MiniTable_Field* field, - int wire_type, wireval* val, int* op) { - switch (wire_type) { - case kUpb_WireType_Varint: - ptr = decode_varint64(d, ptr, &val->uint64_val); - *op = varint_ops[field->descriptortype]; - decode_munge(field->descriptortype, val); - return ptr; - case kUpb_WireType_32Bit: - memcpy(&val->uint32_val, ptr, 4); - val->uint32_val = _upb_BigEndian_Swap32(val->uint32_val); - *op = OP_SCALAR_LG2(2); - if (((1 << field->descriptortype) & FIXED32_OK_MASK) == 0) { - *op = OP_UNKNOWN; - } - return ptr + 4; - case kUpb_WireType_64Bit: - memcpy(&val->uint64_val, ptr, 8); - val->uint64_val = _upb_BigEndian_Swap64(val->uint64_val); - *op = OP_SCALAR_LG2(3); - if (((1 << field->descriptortype) & FIXED64_OK_MASK) == 0) { - *op = OP_UNKNOWN; - } - return ptr + 8; - case kUpb_WireType_Delimited: { - int ndx = field->descriptortype; - uint64_t size; - if (upb_FieldMode_Get(field) == kUpb_FieldMode_Array) ndx += TYPE_COUNT; - ptr = decode_varint64(d, ptr, &size); - if (size >= INT32_MAX || ptr - d->end + (int32_t)size > d->limit) { - break; /* Length overflow. */ - } - *op = delim_ops[ndx]; - val->size = size; - return ptr; - } - case kUpb_WireType_StartGroup: - val->uint32_val = field->number; - if (field->descriptortype == kUpb_FieldType_Group) { - *op = OP_SUBMSG; - } else if (field->descriptortype == TYPE_MSGSET_ITEM) { - *op = OP_MSGSET_ITEM; - } else { - *op = OP_UNKNOWN; - } - return ptr; - default: - break; - } - return decode_err(d, kUpb_DecodeStatus_Malformed); -} +const upb_MiniTable google_protobuf_FieldDescriptorProto_msg_init = { + &google_protobuf_FieldDescriptorProto_submsgs[0], + &google_protobuf_FieldDescriptorProto__fields[0], + UPB_SIZE(72, 112), 11, kUpb_ExtMode_NonExtendable, 10, 255, 0, +}; -UPB_FORCEINLINE -static const char* decode_known(upb_Decoder* d, const char* ptr, - upb_Message* msg, const upb_MiniTable* layout, - const upb_MiniTable_Field* field, int op, - wireval* val) { - const upb_MiniTable_Sub* subs = layout->subs; - uint8_t mode = field->mode; +static const upb_MiniTable_Sub google_protobuf_OneofDescriptorProto_submsgs[1] = { + {.submsg = &google_protobuf_OneofOptions_msg_init}, +}; - if (UPB_UNLIKELY(mode & upb_LabelFlags_IsExtension)) { - const upb_MiniTable_Extension* ext_layout = - (const upb_MiniTable_Extension*)field; - upb_Message_Extension* ext = - _upb_Message_Getorcreateext(msg, ext_layout, &d->arena); - if (UPB_UNLIKELY(!ext)) return decode_err(d, kUpb_DecodeStatus_OutOfMemory); - msg = &ext->data; - subs = &ext->ext->sub; - } +static const upb_MiniTable_Field google_protobuf_OneofDescriptorProto__fields[2] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(2, 2), 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - switch (mode & kUpb_FieldMode_Mask) { - case kUpb_FieldMode_Array: - return decode_toarray(d, ptr, msg, subs, field, val, op); - case kUpb_FieldMode_Map: - return decode_tomap(d, ptr, msg, subs, field, val); - case kUpb_FieldMode_Scalar: - return decode_tomsg(d, ptr, msg, subs, field, val, op); - default: - UPB_UNREACHABLE(); - } -} +const upb_MiniTable google_protobuf_OneofDescriptorProto_msg_init = { + &google_protobuf_OneofDescriptorProto_submsgs[0], + &google_protobuf_OneofDescriptorProto__fields[0], + UPB_SIZE(16, 32), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, +}; -static const char* decode_reverse_skip_varint(const char* ptr, uint32_t val) { - uint32_t seen = 0; - do { - ptr--; - seen <<= 7; - seen |= *ptr & 0x7f; - } while (seen != val); - return ptr; -} +static const upb_MiniTable_Sub google_protobuf_EnumDescriptorProto_submsgs[3] = { + {.submsg = &google_protobuf_EnumValueDescriptorProto_msg_init}, + {.submsg = &google_protobuf_EnumOptions_msg_init}, + {.submsg = &google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init}, +}; -static const char* decode_unknown(upb_Decoder* d, const char* ptr, - upb_Message* msg, int field_number, - int wire_type, wireval val) { - if (field_number == 0) return decode_err(d, kUpb_DecodeStatus_Malformed); +static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto__fields[5] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 32), UPB_SIZE(2, 2), 1, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 40), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(24, 48), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - // Since unknown fields are the uncommon case, we do a little extra work here - // to walk backwards through the buffer to find the field start. This frees - // up a register in the fast paths (when the field is known), which leads to - // significant speedups in benchmarks. - const char* start = ptr; +const upb_MiniTable google_protobuf_EnumDescriptorProto_msg_init = { + &google_protobuf_EnumDescriptorProto_submsgs[0], + &google_protobuf_EnumDescriptorProto__fields[0], + UPB_SIZE(32, 56), 5, kUpb_ExtMode_NonExtendable, 5, 255, 0, +}; - if (wire_type == kUpb_WireType_Delimited) ptr += val.size; - if (msg) { - switch (wire_type) { - case kUpb_WireType_Varint: - case kUpb_WireType_Delimited: - start--; - while (start[-1] & 0x80) start--; - break; - case kUpb_WireType_32Bit: - start -= 4; - break; - case kUpb_WireType_64Bit: - start -= 8; - break; - default: - break; - } +static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = { + {1, UPB_SIZE(4, 4), UPB_SIZE(1, 1), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 8), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; - assert(start == d->debug_valstart); - uint32_t tag = ((uint32_t)field_number << 3) | wire_type; - start = decode_reverse_skip_varint(start, tag); - assert(start == d->debug_tagstart); +const upb_MiniTable google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init = { + NULL, + &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0], + UPB_SIZE(16, 16), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, +}; - if (wire_type == kUpb_WireType_StartGroup) { - d->unknown = start; - d->unknown_msg = msg; - ptr = decode_group(d, ptr, NULL, NULL, field_number); - start = d->unknown; - d->unknown_msg = NULL; - d->unknown = NULL; - } - if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { - return decode_err(d, kUpb_DecodeStatus_OutOfMemory); - } - } else if (wire_type == kUpb_WireType_StartGroup) { - ptr = decode_group(d, ptr, NULL, NULL, field_number); - } - return ptr; -} +static const upb_MiniTable_Sub google_protobuf_EnumValueDescriptorProto_submsgs[1] = { + {.submsg = &google_protobuf_EnumValueOptions_msg_init}, +}; -UPB_NOINLINE -static const char* decode_msg(upb_Decoder* d, const char* ptr, upb_Message* msg, - const upb_MiniTable* layout) { - int last_field_index = 0; +static const upb_MiniTable_Field google_protobuf_EnumValueDescriptorProto__fields[3] = { + {1, UPB_SIZE(8, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(4, 4), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 24), UPB_SIZE(3, 3), 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -#if UPB_FASTTABLE - // The first time we want to skip fast dispatch, because we may have just been - // invoked by the fast parser to handle a case that it bailed on. - if (!decode_isdone(d, &ptr)) goto nofast; -#endif +const upb_MiniTable google_protobuf_EnumValueDescriptorProto_msg_init = { + &google_protobuf_EnumValueDescriptorProto_submsgs[0], + &google_protobuf_EnumValueDescriptorProto__fields[0], + UPB_SIZE(24, 32), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, +}; - while (!decode_isdone(d, &ptr)) { - uint32_t tag; - const upb_MiniTable_Field* field; - int field_number; - int wire_type; - wireval val; - int op; +static const upb_MiniTable_Sub google_protobuf_ServiceDescriptorProto_submsgs[2] = { + {.submsg = &google_protobuf_MethodDescriptorProto_msg_init}, + {.submsg = &google_protobuf_ServiceOptions_msg_init}, +}; - if (decode_tryfastdispatch(d, &ptr, msg, layout)) break; +static const upb_MiniTable_Field google_protobuf_ServiceDescriptorProto__fields[3] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 32), UPB_SIZE(2, 2), 1, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -#if UPB_FASTTABLE - nofast: -#endif +const upb_MiniTable google_protobuf_ServiceDescriptorProto_msg_init = { + &google_protobuf_ServiceDescriptorProto_submsgs[0], + &google_protobuf_ServiceDescriptorProto__fields[0], + UPB_SIZE(24, 40), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, +}; -#ifndef NDEBUG - d->debug_tagstart = ptr; -#endif +static const upb_MiniTable_Sub google_protobuf_MethodDescriptorProto_submsgs[1] = { + {.submsg = &google_protobuf_MethodOptions_msg_init}, +}; - UPB_ASSERT(ptr < d->limit_ptr); - ptr = decode_tag(d, ptr, &tag); - field_number = tag >> 3; - wire_type = tag & 7; +static const upb_MiniTable_Field google_protobuf_MethodDescriptorProto__fields[6] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(20, 40), UPB_SIZE(3, 3), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(28, 56), UPB_SIZE(4, 4), 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(1, 1), UPB_SIZE(5, 5), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(2, 2), UPB_SIZE(6, 6), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +}; -#ifndef NDEBUG - d->debug_valstart = ptr; -#endif +const upb_MiniTable google_protobuf_MethodDescriptorProto_msg_init = { + &google_protobuf_MethodDescriptorProto_submsgs[0], + &google_protobuf_MethodDescriptorProto__fields[0], + UPB_SIZE(32, 64), 6, kUpb_ExtMode_NonExtendable, 6, 255, 0, +}; - if (wire_type == kUpb_WireType_EndGroup) { - d->end_group = field_number; - return ptr; - } +static const upb_MiniTable_Sub google_protobuf_FileOptions_submsgs[2] = { + {.subenum = &google_protobuf_FileOptions_OptimizeMode_enum_init}, + {.submsg = &google_protobuf_UninterpretedOption_msg_init}, +}; - field = decode_findfield(d, layout, field_number, &last_field_index); - ptr = decode_wireval(d, ptr, field, wire_type, &val, &op); +static const upb_MiniTable_Field google_protobuf_FileOptions__fields[21] = { + {1, UPB_SIZE(20, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(28, 40), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(4, 4), UPB_SIZE(3, 3), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(8, 8), UPB_SIZE(4, 4), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {11, UPB_SIZE(36, 56), UPB_SIZE(5, 5), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {16, UPB_SIZE(9, 9), UPB_SIZE(6, 6), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {17, UPB_SIZE(10, 10), UPB_SIZE(7, 7), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {18, UPB_SIZE(11, 11), UPB_SIZE(8, 8), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {20, UPB_SIZE(12, 12), UPB_SIZE(9, 9), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {23, UPB_SIZE(13, 13), UPB_SIZE(10, 10), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {27, UPB_SIZE(14, 14), UPB_SIZE(11, 11), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {31, UPB_SIZE(15, 15), UPB_SIZE(12, 12), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {36, UPB_SIZE(44, 72), UPB_SIZE(13, 13), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {37, UPB_SIZE(52, 88), UPB_SIZE(14, 14), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {39, UPB_SIZE(60, 104), UPB_SIZE(15, 15), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {40, UPB_SIZE(68, 120), UPB_SIZE(16, 16), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {41, UPB_SIZE(76, 136), UPB_SIZE(17, 17), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {42, UPB_SIZE(16, 16), UPB_SIZE(18, 18), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {44, UPB_SIZE(84, 152), UPB_SIZE(19, 19), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {45, UPB_SIZE(92, 168), UPB_SIZE(20, 20), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(100, 184), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - if (op >= 0) { - ptr = decode_known(d, ptr, msg, layout, field, op, &val); - } else { - switch (op) { - case OP_UNKNOWN: - ptr = decode_unknown(d, ptr, msg, field_number, wire_type, val); - break; - case OP_MSGSET_ITEM: - ptr = decode_msgset(d, ptr, msg, layout); - break; - case OP_MSGSET_TYPEID: { - const upb_MiniTable_Extension* ext = _upb_extreg_get( - d->extreg, layout->subs[0].submsg, val.uint64_val); - if (ext) ((upb_MiniTable*)layout)->fields = &ext->field; - break; - } - } - } - } +const upb_MiniTable google_protobuf_FileOptions_msg_init = { + &google_protobuf_FileOptions_submsgs[0], + &google_protobuf_FileOptions__fields[0], + UPB_SIZE(104, 192), 21, kUpb_ExtMode_Extendable, 1, 255, 0, +}; - return UPB_UNLIKELY(layout && layout->required_count) - ? decode_checkrequired(d, ptr, msg, layout) - : ptr; -} +static const upb_MiniTable_Sub google_protobuf_MessageOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msg_init}, +}; -const char* fastdecode_generic(struct upb_Decoder* d, const char* ptr, - upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t data) { - (void)data; - *(uint32_t*)msg |= hasbits; - return decode_msg(d, ptr, msg, decode_totablep(table)); -} +static const upb_MiniTable_Field google_protobuf_MessageOptions__fields[5] = { + {1, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(2, 2), UPB_SIZE(2, 2), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(3, 3), UPB_SIZE(3, 3), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(4, 4), UPB_SIZE(4, 4), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(8, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -static upb_DecodeStatus decode_top(struct upb_Decoder* d, const char* buf, - void* msg, const upb_MiniTable* l) { - if (!decode_tryfastdispatch(d, &buf, msg, l)) { - decode_msg(d, buf, msg, l); - } - if (d->end_group != DECODE_NOGROUP) return kUpb_DecodeStatus_Malformed; - if (d->missing_required) return kUpb_DecodeStatus_MissingRequired; - return kUpb_DecodeStatus_Ok; -} +const upb_MiniTable google_protobuf_MessageOptions_msg_init = { + &google_protobuf_MessageOptions_submsgs[0], + &google_protobuf_MessageOptions__fields[0], + UPB_SIZE(16, 16), 5, kUpb_ExtMode_Extendable, 3, 255, 0, +}; -upb_DecodeStatus upb_Decode(const char* buf, size_t size, void* msg, - const upb_MiniTable* l, - const upb_ExtensionRegistry* extreg, int options, - upb_Arena* arena) { - upb_Decoder state; - unsigned depth = (unsigned)options >> 16; +static const upb_MiniTable_Sub google_protobuf_FieldOptions_submsgs[3] = { + {.subenum = &google_protobuf_FieldOptions_CType_enum_init}, + {.subenum = &google_protobuf_FieldOptions_JSType_enum_init}, + {.submsg = &google_protobuf_UninterpretedOption_msg_init}, +}; - if (size <= 16) { - memset(&state.patch, 0, 32); - if (size) memcpy(&state.patch, buf, size); - buf = state.patch; - state.end = buf + size; - state.limit = 0; - options &= ~kUpb_DecodeOption_AliasString; // Can't alias patch buf. - } else { - state.end = buf + size - 16; - state.limit = 16; - } +static const upb_MiniTable_Field google_protobuf_FieldOptions__fields[8] = { + {1, UPB_SIZE(4, 4), UPB_SIZE(1, 1), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 8), UPB_SIZE(2, 2), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(9, 9), UPB_SIZE(3, 3), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(10, 10), UPB_SIZE(4, 4), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(12, 12), UPB_SIZE(5, 5), 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(16, 16), UPB_SIZE(6, 6), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {15, UPB_SIZE(17, 17), UPB_SIZE(7, 7), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(20, 24), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - state.extreg = extreg; - state.limit_ptr = state.end; - state.unknown_msg = NULL; - state.depth = depth ? depth : 64; - state.end_group = DECODE_NOGROUP; - state.options = (uint16_t)options; - state.missing_required = false; - state.arena.head = arena->head; - state.arena.last_size = arena->last_size; - state.arena.cleanup_metadata = arena->cleanup_metadata; - state.arena.parent = arena; +const upb_MiniTable google_protobuf_FieldOptions_msg_init = { + &google_protobuf_FieldOptions_submsgs[0], + &google_protobuf_FieldOptions__fields[0], + UPB_SIZE(24, 32), 8, kUpb_ExtMode_Extendable, 3, 255, 0, +}; - upb_DecodeStatus status = UPB_SETJMP(state.err); - if (UPB_LIKELY(status == kUpb_DecodeStatus_Ok)) { - status = decode_top(&state, buf, msg, l); - } +static const upb_MiniTable_Sub google_protobuf_OneofOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msg_init}, +}; - arena->head.ptr = state.arena.head.ptr; - arena->head.end = state.arena.head.end; - arena->cleanup_metadata = state.arena.cleanup_metadata; - return status; -} +static const upb_MiniTable_Field google_protobuf_OneofOptions__fields[1] = { + {999, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -#undef OP_UNKNOWN -#undef OP_SKIP -#undef OP_SCALAR_LG2 -#undef OP_FIXPCK_LG2 -#undef OP_VARPCK_LG2 -#undef OP_STRING -#undef OP_BYTES -#undef OP_SUBMSG +const upb_MiniTable google_protobuf_OneofOptions_msg_init = { + &google_protobuf_OneofOptions_submsgs[0], + &google_protobuf_OneofOptions__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_Extendable, 0, 255, 0, +}; -/** upb/encode.c ************************************************************/ -/* We encode backwards, to avoid pre-computing lengths (one-pass encode). */ +static const upb_MiniTable_Sub google_protobuf_EnumOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msg_init}, +}; +static const upb_MiniTable_Field google_protobuf_EnumOptions__fields[3] = { + {2, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(2, 2), UPB_SIZE(2, 2), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -#include -#include +const upb_MiniTable google_protobuf_EnumOptions_msg_init = { + &google_protobuf_EnumOptions_submsgs[0], + &google_protobuf_EnumOptions__fields[0], + UPB_SIZE(8, 16), 3, kUpb_ExtMode_Extendable, 0, 255, 0, +}; +static const upb_MiniTable_Sub google_protobuf_EnumValueOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msg_init}, +}; -/* Must be last. */ +static const upb_MiniTable_Field google_protobuf_EnumValueOptions__fields[2] = { + {1, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -#define UPB_PB_VARINT_MAX_LEN 10 +const upb_MiniTable google_protobuf_EnumValueOptions_msg_init = { + &google_protobuf_EnumValueOptions_submsgs[0], + &google_protobuf_EnumValueOptions__fields[0], + UPB_SIZE(8, 16), 2, kUpb_ExtMode_Extendable, 1, 255, 0, +}; -UPB_NOINLINE -static size_t encode_varint64(uint64_t val, char* buf) { - size_t i = 0; - do { - uint8_t byte = val & 0x7fU; - val >>= 7; - if (val) byte |= 0x80U; - buf[i++] = byte; - } while (val); - return i; -} +static const upb_MiniTable_Sub google_protobuf_ServiceOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msg_init}, +}; -static uint32_t encode_zz32(int32_t n) { - return ((uint32_t)n << 1) ^ (n >> 31); -} -static uint64_t encode_zz64(int64_t n) { - return ((uint64_t)n << 1) ^ (n >> 63); -} +static const upb_MiniTable_Field google_protobuf_ServiceOptions__fields[2] = { + {33, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -typedef struct { - jmp_buf err; - upb_alloc* alloc; - char *buf, *ptr, *limit; - int options; - int depth; - _upb_mapsorter sorter; -} upb_encstate; +const upb_MiniTable google_protobuf_ServiceOptions_msg_init = { + &google_protobuf_ServiceOptions_submsgs[0], + &google_protobuf_ServiceOptions__fields[0], + UPB_SIZE(8, 16), 2, kUpb_ExtMode_Extendable, 0, 255, 0, +}; -static size_t upb_roundup_pow2(size_t bytes) { - size_t ret = 128; - while (ret < bytes) { - ret *= 2; - } - return ret; -} +static const upb_MiniTable_Sub google_protobuf_MethodOptions_submsgs[2] = { + {.subenum = &google_protobuf_MethodOptions_IdempotencyLevel_enum_init}, + {.submsg = &google_protobuf_UninterpretedOption_msg_init}, +}; -UPB_NORETURN static void encode_err(upb_encstate* e) { UPB_LONGJMP(e->err, 1); } +static const upb_MiniTable_Field google_protobuf_MethodOptions__fields[3] = { + {33, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {34, UPB_SIZE(4, 4), UPB_SIZE(2, 2), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(8, 8), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -UPB_NOINLINE -static void encode_growbuffer(upb_encstate* e, size_t bytes) { - size_t old_size = e->limit - e->buf; - size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr)); - char* new_buf = upb_realloc(e->alloc, e->buf, old_size, new_size); +const upb_MiniTable google_protobuf_MethodOptions_msg_init = { + &google_protobuf_MethodOptions_submsgs[0], + &google_protobuf_MethodOptions__fields[0], + UPB_SIZE(16, 16), 3, kUpb_ExtMode_Extendable, 0, 255, 0, +}; - if (!new_buf) encode_err(e); +static const upb_MiniTable_Sub google_protobuf_UninterpretedOption_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_NamePart_msg_init}, +}; - /* We want previous data at the end, realloc() put it at the beginning. */ - if (old_size > 0) { - memmove(new_buf + new_size - old_size, e->buf, old_size); - } +static const upb_MiniTable_Field google_protobuf_UninterpretedOption__fields[7] = { + {2, UPB_SIZE(4, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(8, 16), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(32, 64), UPB_SIZE(2, 2), kUpb_NoSub, 4, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(40, 72), UPB_SIZE(3, 3), kUpb_NoSub, 3, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(48, 80), UPB_SIZE(4, 4), kUpb_NoSub, 1, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(16, 32), UPB_SIZE(5, 5), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(24, 48), UPB_SIZE(6, 6), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, +}; - e->ptr = new_buf + new_size - (e->limit - e->ptr); - e->limit = new_buf + new_size; - e->buf = new_buf; +const upb_MiniTable google_protobuf_UninterpretedOption_msg_init = { + &google_protobuf_UninterpretedOption_submsgs[0], + &google_protobuf_UninterpretedOption__fields[0], + UPB_SIZE(56, 88), 7, kUpb_ExtMode_NonExtendable, 0, 255, 0, +}; - e->ptr -= bytes; -} +static const upb_MiniTable_Field google_protobuf_UninterpretedOption_NamePart__fields[2] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(1, 1), UPB_SIZE(2, 2), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +}; -/* Call to ensure that at least "bytes" bytes are available for writing at - * e->ptr. Returns false if the bytes could not be allocated. */ -UPB_FORCEINLINE -static void encode_reserve(upb_encstate* e, size_t bytes) { - if ((size_t)(e->ptr - e->buf) < bytes) { - encode_growbuffer(e, bytes); - return; - } +const upb_MiniTable google_protobuf_UninterpretedOption_NamePart_msg_init = { + NULL, + &google_protobuf_UninterpretedOption_NamePart__fields[0], + UPB_SIZE(16, 24), 2, kUpb_ExtMode_NonExtendable, 2, 255, 2, +}; - e->ptr -= bytes; -} +static const upb_MiniTable_Sub google_protobuf_SourceCodeInfo_submsgs[1] = { + {.submsg = &google_protobuf_SourceCodeInfo_Location_msg_init}, +}; -/* Writes the given bytes to the buffer, handling reserve/advance. */ -static void encode_bytes(upb_encstate* e, const void* data, size_t len) { - if (len == 0) return; /* memcpy() with zero size is UB */ - encode_reserve(e, len); - memcpy(e->ptr, data, len); -} +static const upb_MiniTable_Field google_protobuf_SourceCodeInfo__fields[1] = { + {1, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -static void encode_fixed64(upb_encstate* e, uint64_t val) { - val = _upb_BigEndian_Swap64(val); - encode_bytes(e, &val, sizeof(uint64_t)); -} +const upb_MiniTable google_protobuf_SourceCodeInfo_msg_init = { + &google_protobuf_SourceCodeInfo_submsgs[0], + &google_protobuf_SourceCodeInfo__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, +}; -static void encode_fixed32(upb_encstate* e, uint32_t val) { - val = _upb_BigEndian_Swap32(val); - encode_bytes(e, &val, sizeof(uint32_t)); -} +static const upb_MiniTable_Field google_protobuf_SourceCodeInfo_Location__fields[5] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 16), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(12, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 40), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(28, 56), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -UPB_NOINLINE -static void encode_longvarint(upb_encstate* e, uint64_t val) { - size_t len; - char* start; +const upb_MiniTable google_protobuf_SourceCodeInfo_Location_msg_init = { + NULL, + &google_protobuf_SourceCodeInfo_Location__fields[0], + UPB_SIZE(32, 64), 5, kUpb_ExtMode_NonExtendable, 4, 255, 0, +}; - encode_reserve(e, UPB_PB_VARINT_MAX_LEN); - len = encode_varint64(val, e->ptr); - start = e->ptr + UPB_PB_VARINT_MAX_LEN - len; - memmove(start, e->ptr, len); - e->ptr = start; -} +static const upb_MiniTable_Sub google_protobuf_GeneratedCodeInfo_submsgs[1] = { + {.submsg = &google_protobuf_GeneratedCodeInfo_Annotation_msg_init}, +}; -UPB_FORCEINLINE -static void encode_varint(upb_encstate* e, uint64_t val) { - if (val < 128 && e->ptr != e->buf) { - --e->ptr; - *e->ptr = val; - } else { - encode_longvarint(e, val); - } -} +static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo__fields[1] = { + {1, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -static void encode_double(upb_encstate* e, double d) { - uint64_t u64; - UPB_ASSERT(sizeof(double) == sizeof(uint64_t)); - memcpy(&u64, &d, sizeof(uint64_t)); - encode_fixed64(e, u64); -} +const upb_MiniTable google_protobuf_GeneratedCodeInfo_msg_init = { + &google_protobuf_GeneratedCodeInfo_submsgs[0], + &google_protobuf_GeneratedCodeInfo__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, +}; -static void encode_float(upb_encstate* e, float d) { - uint32_t u32; - UPB_ASSERT(sizeof(float) == sizeof(uint32_t)); - memcpy(&u32, &d, sizeof(uint32_t)); - encode_fixed32(e, u32); -} +static const upb_MiniTable_Sub google_protobuf_GeneratedCodeInfo_Annotation_submsgs[1] = { + {.subenum = &google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init}, +}; -static void encode_tag(upb_encstate* e, uint32_t field_number, - uint8_t wire_type) { - encode_varint(e, (field_number << 3) | wire_type); -} +static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo_Annotation__fields[5] = { + {1, UPB_SIZE(16, 16), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(20, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(4, 4), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(8, 8), UPB_SIZE(3, 3), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(12, 12), UPB_SIZE(4, 4), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; -static void encode_fixedarray(upb_encstate* e, const upb_Array* arr, - size_t elem_size, uint32_t tag) { - size_t bytes = arr->len * elem_size; - const char* data = _upb_array_constptr(arr); - const char* ptr = data + bytes - elem_size; +const upb_MiniTable google_protobuf_GeneratedCodeInfo_Annotation_msg_init = { + &google_protobuf_GeneratedCodeInfo_Annotation_submsgs[0], + &google_protobuf_GeneratedCodeInfo_Annotation__fields[0], + UPB_SIZE(32, 40), 5, kUpb_ExtMode_NonExtendable, 5, 255, 0, +}; - if (tag || !_upb_IsLittleEndian()) { - while (true) { - if (elem_size == 4) { - uint32_t val; - memcpy(&val, ptr, sizeof(val)); - val = _upb_BigEndian_Swap32(val); - encode_bytes(e, &val, elem_size); - } else { - UPB_ASSERT(elem_size == 8); - uint64_t val; - memcpy(&val, ptr, sizeof(val)); - val = _upb_BigEndian_Swap64(val); - encode_bytes(e, &val, elem_size); - } +static const upb_MiniTable *messages_layout[27] = { + &google_protobuf_FileDescriptorSet_msg_init, + &google_protobuf_FileDescriptorProto_msg_init, + &google_protobuf_DescriptorProto_msg_init, + &google_protobuf_DescriptorProto_ExtensionRange_msg_init, + &google_protobuf_DescriptorProto_ReservedRange_msg_init, + &google_protobuf_ExtensionRangeOptions_msg_init, + &google_protobuf_FieldDescriptorProto_msg_init, + &google_protobuf_OneofDescriptorProto_msg_init, + &google_protobuf_EnumDescriptorProto_msg_init, + &google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init, + &google_protobuf_EnumValueDescriptorProto_msg_init, + &google_protobuf_ServiceDescriptorProto_msg_init, + &google_protobuf_MethodDescriptorProto_msg_init, + &google_protobuf_FileOptions_msg_init, + &google_protobuf_MessageOptions_msg_init, + &google_protobuf_FieldOptions_msg_init, + &google_protobuf_OneofOptions_msg_init, + &google_protobuf_EnumOptions_msg_init, + &google_protobuf_EnumValueOptions_msg_init, + &google_protobuf_ServiceOptions_msg_init, + &google_protobuf_MethodOptions_msg_init, + &google_protobuf_UninterpretedOption_msg_init, + &google_protobuf_UninterpretedOption_NamePart_msg_init, + &google_protobuf_SourceCodeInfo_msg_init, + &google_protobuf_SourceCodeInfo_Location_msg_init, + &google_protobuf_GeneratedCodeInfo_msg_init, + &google_protobuf_GeneratedCodeInfo_Annotation_msg_init, +}; - if (tag) encode_varint(e, tag); - if (ptr == data) break; - ptr -= elem_size; - } - } else { - encode_bytes(e, data, bytes); - } -} +const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enum_init = { + 64, + 0, + { + 0x7fffe, + 0x0, + }, +}; -static void encode_message(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable* m, size_t* size); +const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enum_init = { + 64, + 0, + { + 0xe, + 0x0, + }, +}; -static void encode_scalar(upb_encstate* e, const void* _field_mem, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { - const char* field_mem = _field_mem; - int wire_type; +const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enum_init = { + 64, + 0, + { + 0xe, + 0x0, + }, +}; -#define CASE(ctype, type, wtype, encodeval) \ - { \ - ctype val = *(ctype*)field_mem; \ - encode_##type(e, encodeval); \ - wire_type = wtype; \ - break; \ - } +const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; - switch (f->descriptortype) { - case kUpb_FieldType_Double: - CASE(double, double, kUpb_WireType_64Bit, val); - case kUpb_FieldType_Float: - CASE(float, float, kUpb_WireType_32Bit, val); - case kUpb_FieldType_Int64: - case kUpb_FieldType_UInt64: - CASE(uint64_t, varint, kUpb_WireType_Varint, val); - case kUpb_FieldType_UInt32: - CASE(uint32_t, varint, kUpb_WireType_Varint, val); - case kUpb_FieldType_Int32: - case kUpb_FieldType_Enum: - CASE(int32_t, varint, kUpb_WireType_Varint, (int64_t)val); - case kUpb_FieldType_SFixed64: - case kUpb_FieldType_Fixed64: - CASE(uint64_t, fixed64, kUpb_WireType_64Bit, val); - case kUpb_FieldType_Fixed32: - case kUpb_FieldType_SFixed32: - CASE(uint32_t, fixed32, kUpb_WireType_32Bit, val); - case kUpb_FieldType_Bool: - CASE(bool, varint, kUpb_WireType_Varint, val); - case kUpb_FieldType_SInt32: - CASE(int32_t, varint, kUpb_WireType_Varint, encode_zz32(val)); - case kUpb_FieldType_SInt64: - CASE(int64_t, varint, kUpb_WireType_Varint, encode_zz64(val)); - case kUpb_FieldType_String: - case kUpb_FieldType_Bytes: { - upb_StringView view = *(upb_StringView*)field_mem; - encode_bytes(e, view.data, view.size); - encode_varint(e, view.size); - wire_type = kUpb_WireType_Delimited; - break; - } - case kUpb_FieldType_Group: { - size_t size; - void* submsg = *(void**)field_mem; - const upb_MiniTable* subm = subs[f->submsg_index].submsg; - if (submsg == NULL) { - return; - } - if (--e->depth == 0) encode_err(e); - encode_tag(e, f->number, kUpb_WireType_EndGroup); - encode_message(e, submsg, subm, &size); - wire_type = kUpb_WireType_StartGroup; - e->depth++; +const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTable_Enum google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +static const upb_MiniTable_Enum *enums_layout[7] = { + &google_protobuf_FieldDescriptorProto_Type_enum_init, + &google_protobuf_FieldDescriptorProto_Label_enum_init, + &google_protobuf_FileOptions_OptimizeMode_enum_init, + &google_protobuf_FieldOptions_CType_enum_init, + &google_protobuf_FieldOptions_JSType_enum_init, + &google_protobuf_MethodOptions_IdempotencyLevel_enum_init, + &google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init, +}; + +const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout = { + messages_layout, + enums_layout, + NULL, + 27, + 7, + 0, +}; + + +/* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/descriptor.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ + + +static const char descriptor[7820] = {'\n', ' ', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'e', 's', 'c', 'r', 'i', 'p', +'t', 'o', 'r', '.', 'p', 'r', 'o', 't', 'o', '\022', '\017', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', +'f', '\"', 'M', '\n', '\021', 'F', 'i', 'l', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'S', 'e', 't', '\022', '8', '\n', +'\004', 'f', 'i', 'l', 'e', '\030', '\001', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', +'o', 'b', 'u', 'f', '.', 'F', 'i', 'l', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', +'\004', 'f', 'i', 'l', 'e', '\"', '\376', '\004', '\n', '\023', 'F', 'i', 'l', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', +'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', +'\030', '\n', '\007', 'p', 'a', 'c', 'k', 'a', 'g', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\007', 'p', 'a', 'c', 'k', 'a', 'g', 'e', +'\022', '\036', '\n', '\n', 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'y', '\030', '\003', ' ', '\003', '(', '\t', 'R', '\n', 'd', 'e', 'p', +'e', 'n', 'd', 'e', 'n', 'c', 'y', '\022', '+', '\n', '\021', 'p', 'u', 'b', 'l', 'i', 'c', '_', 'd', 'e', 'p', 'e', 'n', 'd', 'e', +'n', 'c', 'y', '\030', '\n', ' ', '\003', '(', '\005', 'R', '\020', 'p', 'u', 'b', 'l', 'i', 'c', 'D', 'e', 'p', 'e', 'n', 'd', 'e', 'n', +'c', 'y', '\022', '\'', '\n', '\017', 'w', 'e', 'a', 'k', '_', 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'y', '\030', '\013', ' ', '\003', +'(', '\005', 'R', '\016', 'w', 'e', 'a', 'k', 'D', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'y', '\022', 'C', '\n', '\014', 'm', 'e', 's', +'s', 'a', 'g', 'e', '_', 't', 'y', 'p', 'e', '\030', '\004', ' ', '\003', '(', '\013', '2', ' ', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', +'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', +'\013', 'm', 'e', 's', 's', 'a', 'g', 'e', 'T', 'y', 'p', 'e', '\022', 'A', '\n', '\t', 'e', 'n', 'u', 'm', '_', 't', 'y', 'p', 'e', +'\030', '\005', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', +'E', 'n', 'u', 'm', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\010', 'e', 'n', 'u', 'm', +'T', 'y', 'p', 'e', '\022', 'A', '\n', '\007', 's', 'e', 'r', 'v', 'i', 'c', 'e', '\030', '\006', ' ', '\003', '(', '\013', '2', '\'', '.', 'g', +'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'D', 'e', 's', +'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\007', 's', 'e', 'r', 'v', 'i', 'c', 'e', '\022', 'C', '\n', '\t', +'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\030', '\007', ' ', '\003', '(', '\013', '2', '%', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', +'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', +'r', 'o', 't', 'o', 'R', '\t', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\022', '6', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', +'s', '\030', '\010', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', +'.', 'F', 'i', 'l', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\022', 'I', '\n', '\020', +'s', 'o', 'u', 'r', 'c', 'e', '_', 'c', 'o', 'd', 'e', '_', 'i', 'n', 'f', 'o', '\030', '\t', ' ', '\001', '(', '\013', '2', '\037', '.', +'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 'o', 'u', 'r', 'c', 'e', 'C', 'o', 'd', +'e', 'I', 'n', 'f', 'o', 'R', '\016', 's', 'o', 'u', 'r', 'c', 'e', 'C', 'o', 'd', 'e', 'I', 'n', 'f', 'o', '\022', '\026', '\n', '\006', +'s', 'y', 'n', 't', 'a', 'x', '\030', '\014', ' ', '\001', '(', '\t', 'R', '\006', 's', 'y', 'n', 't', 'a', 'x', '\022', '\030', '\n', '\007', 'e', +'d', 'i', 't', 'i', 'o', 'n', '\030', '\r', ' ', '\001', '(', '\t', 'R', '\007', 'e', 'd', 'i', 't', 'i', 'o', 'n', '\"', '\271', '\006', '\n', +'\017', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', +'\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', ';', '\n', '\005', 'f', 'i', 'e', 'l', 'd', '\030', '\002', ' ', '\003', '(', +'\013', '2', '%', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', +'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\005', 'f', 'i', 'e', 'l', 'd', '\022', 'C', '\n', +'\t', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\030', '\006', ' ', '\003', '(', '\013', '2', '%', '.', 'g', 'o', 'o', 'g', 'l', 'e', +'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', +'P', 'r', 'o', 't', 'o', 'R', '\t', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\022', 'A', '\n', '\013', 'n', 'e', 's', 't', 'e', +'d', '_', 't', 'y', 'p', 'e', '\030', '\003', ' ', '\003', '(', '\013', '2', ' ', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', +'t', 'o', 'b', 'u', 'f', '.', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\n', 'n', 'e', +'s', 't', 'e', 'd', 'T', 'y', 'p', 'e', '\022', 'A', '\n', '\t', 'e', 'n', 'u', 'm', '_', 't', 'y', 'p', 'e', '\030', '\004', ' ', '\003', +'(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'E', 'n', 'u', 'm', +'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\010', 'e', 'n', 'u', 'm', 'T', 'y', 'p', 'e', +'\022', 'X', '\n', '\017', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '_', 'r', 'a', 'n', 'g', 'e', '\030', '\005', ' ', '\003', '(', '\013', +'2', '/', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'e', 's', 'c', 'r', 'i', +'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '.', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', 'e', 'R', +'\016', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', 'e', '\022', 'D', '\n', '\n', 'o', 'n', 'e', 'o', 'f', '_', +'d', 'e', 'c', 'l', '\030', '\010', ' ', '\003', '(', '\013', '2', '%', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', +'b', 'u', 'f', '.', 'O', 'n', 'e', 'o', 'f', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', +'\t', 'o', 'n', 'e', 'o', 'f', 'D', 'e', 'c', 'l', '\022', '9', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\007', ' ', '\001', +'(', '\013', '2', '\037', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'M', 'e', 's', 's', +'a', 'g', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\022', 'U', '\n', '\016', 'r', 'e', +'s', 'e', 'r', 'v', 'e', 'd', '_', 'r', 'a', 'n', 'g', 'e', '\030', '\t', ' ', '\003', '(', '\013', '2', '.', '.', 'g', 'o', 'o', 'g', +'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', +'t', 'o', '.', 'R', 'e', 's', 'e', 'r', 'v', 'e', 'd', 'R', 'a', 'n', 'g', 'e', 'R', '\r', 'r', 'e', 's', 'e', 'r', 'v', 'e', +'d', 'R', 'a', 'n', 'g', 'e', '\022', '#', '\n', '\r', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', '_', 'n', 'a', 'm', 'e', '\030', '\n', +' ', '\003', '(', '\t', 'R', '\014', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', 'N', 'a', 'm', 'e', '\032', 'z', '\n', '\016', 'E', 'x', 't', +'e', 'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', 'e', '\022', '\024', '\n', '\005', 's', 't', 'a', 'r', 't', '\030', '\001', ' ', '\001', '(', +'\005', 'R', '\005', 's', 't', 'a', 'r', 't', '\022', '\020', '\n', '\003', 'e', 'n', 'd', '\030', '\002', ' ', '\001', '(', '\005', 'R', '\003', 'e', 'n', +'d', '\022', '@', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\003', ' ', '\001', '(', '\013', '2', '&', '.', 'g', 'o', 'o', 'g', +'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', +'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\032', '7', '\n', '\r', 'R', 'e', 's', 'e', +'r', 'v', 'e', 'd', 'R', 'a', 'n', 'g', 'e', '\022', '\024', '\n', '\005', 's', 't', 'a', 'r', 't', '\030', '\001', ' ', '\001', '(', '\005', 'R', +'\005', 's', 't', 'a', 'r', 't', '\022', '\020', '\n', '\003', 'e', 'n', 'd', '\030', '\002', ' ', '\001', '(', '\005', 'R', '\003', 'e', 'n', 'd', '\"', +'|', '\n', '\025', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', +'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', +'\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', +'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', +'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', +'\"', '\301', '\006', '\n', '\024', 'F', 'i', 'e', 'l', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', +'\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\026', '\n', '\006', 'n', +'u', 'm', 'b', 'e', 'r', '\030', '\003', ' ', '\001', '(', '\005', 'R', '\006', 'n', 'u', 'm', 'b', 'e', 'r', '\022', 'A', '\n', '\005', 'l', 'a', +'b', 'e', 'l', '\030', '\004', ' ', '\001', '(', '\016', '2', '+', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', +'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '.', 'L', +'a', 'b', 'e', 'l', 'R', '\005', 'l', 'a', 'b', 'e', 'l', '\022', '>', '\n', '\004', 't', 'y', 'p', 'e', '\030', '\005', ' ', '\001', '(', '\016', +'2', '*', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'D', +'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '.', 'T', 'y', 'p', 'e', 'R', '\004', 't', 'y', 'p', 'e', +'\022', '\033', '\n', '\t', 't', 'y', 'p', 'e', '_', 'n', 'a', 'm', 'e', '\030', '\006', ' ', '\001', '(', '\t', 'R', '\010', 't', 'y', 'p', 'e', +'N', 'a', 'm', 'e', '\022', '\032', '\n', '\010', 'e', 'x', 't', 'e', 'n', 'd', 'e', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\010', 'e', +'x', 't', 'e', 'n', 'd', 'e', 'e', '\022', '#', '\n', '\r', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 'v', 'a', 'l', 'u', 'e', '\030', +'\007', ' ', '\001', '(', '\t', 'R', '\014', 'd', 'e', 'f', 'a', 'u', 'l', 't', 'V', 'a', 'l', 'u', 'e', '\022', '\037', '\n', '\013', 'o', 'n', +'e', 'o', 'f', '_', 'i', 'n', 'd', 'e', 'x', '\030', '\t', ' ', '\001', '(', '\005', 'R', '\n', 'o', 'n', 'e', 'o', 'f', 'I', 'n', 'd', +'e', 'x', '\022', '\033', '\n', '\t', 'j', 's', 'o', 'n', '_', 'n', 'a', 'm', 'e', '\030', '\n', ' ', '\001', '(', '\t', 'R', '\010', 'j', 's', +'o', 'n', 'N', 'a', 'm', 'e', '\022', '7', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\010', ' ', '\001', '(', '\013', '2', '\035', +'.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'O', 'p', 't', +'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\022', '\'', '\n', '\017', 'p', 'r', 'o', 't', 'o', '3', '_', 'o', +'p', 't', 'i', 'o', 'n', 'a', 'l', '\030', '\021', ' ', '\001', '(', '\010', 'R', '\016', 'p', 'r', 'o', 't', 'o', '3', 'O', 'p', 't', 'i', +'o', 'n', 'a', 'l', '\"', '\266', '\002', '\n', '\004', 'T', 'y', 'p', 'e', '\022', '\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'D', 'O', 'U', +'B', 'L', 'E', '\020', '\001', '\022', '\016', '\n', '\n', 'T', 'Y', 'P', 'E', '_', 'F', 'L', 'O', 'A', 'T', '\020', '\002', '\022', '\016', '\n', '\n', +'T', 'Y', 'P', 'E', '_', 'I', 'N', 'T', '6', '4', '\020', '\003', '\022', '\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'U', 'I', 'N', 'T', +'6', '4', '\020', '\004', '\022', '\016', '\n', '\n', 'T', 'Y', 'P', 'E', '_', 'I', 'N', 'T', '3', '2', '\020', '\005', '\022', '\020', '\n', '\014', 'T', +'Y', 'P', 'E', '_', 'F', 'I', 'X', 'E', 'D', '6', '4', '\020', '\006', '\022', '\020', '\n', '\014', 'T', 'Y', 'P', 'E', '_', 'F', 'I', 'X', +'E', 'D', '3', '2', '\020', '\007', '\022', '\r', '\n', '\t', 'T', 'Y', 'P', 'E', '_', 'B', 'O', 'O', 'L', '\020', '\010', '\022', '\017', '\n', '\013', +'T', 'Y', 'P', 'E', '_', 'S', 'T', 'R', 'I', 'N', 'G', '\020', '\t', '\022', '\016', '\n', '\n', 'T', 'Y', 'P', 'E', '_', 'G', 'R', 'O', +'U', 'P', '\020', '\n', '\022', '\020', '\n', '\014', 'T', 'Y', 'P', 'E', '_', 'M', 'E', 'S', 'S', 'A', 'G', 'E', '\020', '\013', '\022', '\016', '\n', +'\n', 'T', 'Y', 'P', 'E', '_', 'B', 'Y', 'T', 'E', 'S', '\020', '\014', '\022', '\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'U', 'I', 'N', +'T', '3', '2', '\020', '\r', '\022', '\r', '\n', '\t', 'T', 'Y', 'P', 'E', '_', 'E', 'N', 'U', 'M', '\020', '\016', '\022', '\021', '\n', '\r', 'T', +'Y', 'P', 'E', '_', 'S', 'F', 'I', 'X', 'E', 'D', '3', '2', '\020', '\017', '\022', '\021', '\n', '\r', 'T', 'Y', 'P', 'E', '_', 'S', 'F', +'I', 'X', 'E', 'D', '6', '4', '\020', '\020', '\022', '\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'S', 'I', 'N', 'T', '3', '2', '\020', '\021', +'\022', '\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'S', 'I', 'N', 'T', '6', '4', '\020', '\022', '\"', 'C', '\n', '\005', 'L', 'a', 'b', 'e', +'l', '\022', '\022', '\n', '\016', 'L', 'A', 'B', 'E', 'L', '_', 'O', 'P', 'T', 'I', 'O', 'N', 'A', 'L', '\020', '\001', '\022', '\022', '\n', '\016', +'L', 'A', 'B', 'E', 'L', '_', 'R', 'E', 'Q', 'U', 'I', 'R', 'E', 'D', '\020', '\002', '\022', '\022', '\n', '\016', 'L', 'A', 'B', 'E', 'L', +'_', 'R', 'E', 'P', 'E', 'A', 'T', 'E', 'D', '\020', '\003', '\"', 'c', '\n', '\024', 'O', 'n', 'e', 'o', 'f', 'D', 'e', 's', 'c', 'r', +'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', +'\004', 'n', 'a', 'm', 'e', '\022', '7', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\002', ' ', '\001', '(', '\013', '2', '\035', '.', +'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'O', 'n', 'e', 'o', 'f', 'O', 'p', 't', 'i', +'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\"', '\343', '\002', '\n', '\023', 'E', 'n', 'u', 'm', 'D', 'e', 's', 'c', +'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', +'R', '\004', 'n', 'a', 'm', 'e', '\022', '?', '\n', '\005', 'v', 'a', 'l', 'u', 'e', '\030', '\002', ' ', '\003', '(', '\013', '2', ')', '.', 'g', +'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'E', 'n', 'u', 'm', 'V', 'a', 'l', 'u', 'e', 'D', +'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\005', 'v', 'a', 'l', 'u', 'e', '\022', '6', '\n', '\007', +'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\003', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', +'o', 't', 'o', 'b', 'u', 'f', '.', 'E', 'n', 'u', 'm', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', +'n', 's', '\022', ']', '\n', '\016', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', '_', 'r', 'a', 'n', 'g', 'e', '\030', '\004', ' ', '\003', '(', +'\013', '2', '6', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'E', 'n', 'u', 'm', 'D', +'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '.', 'E', 'n', 'u', 'm', 'R', 'e', 's', 'e', 'r', 'v', +'e', 'd', 'R', 'a', 'n', 'g', 'e', 'R', '\r', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', 'R', 'a', 'n', 'g', 'e', '\022', '#', '\n', +'\r', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', '_', 'n', 'a', 'm', 'e', '\030', '\005', ' ', '\003', '(', '\t', 'R', '\014', 'r', 'e', 's', +'e', 'r', 'v', 'e', 'd', 'N', 'a', 'm', 'e', '\032', ';', '\n', '\021', 'E', 'n', 'u', 'm', 'R', 'e', 's', 'e', 'r', 'v', 'e', 'd', +'R', 'a', 'n', 'g', 'e', '\022', '\024', '\n', '\005', 's', 't', 'a', 'r', 't', '\030', '\001', ' ', '\001', '(', '\005', 'R', '\005', 's', 't', 'a', +'r', 't', '\022', '\020', '\n', '\003', 'e', 'n', 'd', '\030', '\002', ' ', '\001', '(', '\005', 'R', '\003', 'e', 'n', 'd', '\"', '\203', '\001', '\n', '\030', +'E', 'n', 'u', 'm', 'V', 'a', 'l', 'u', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '\022', +'\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\026', '\n', '\006', 'n', 'u', +'m', 'b', 'e', 'r', '\030', '\002', ' ', '\001', '(', '\005', 'R', '\006', 'n', 'u', 'm', 'b', 'e', 'r', '\022', ';', '\n', '\007', 'o', 'p', 't', +'i', 'o', 'n', 's', '\030', '\003', ' ', '\001', '(', '\013', '2', '!', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', +'b', 'u', 'f', '.', 'E', 'n', 'u', 'm', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', +'i', 'o', 'n', 's', '\"', '\247', '\001', '\n', '\026', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', +'r', 'P', 'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', +'e', '\022', '>', '\n', '\006', 'm', 'e', 't', 'h', 'o', 'd', '\030', '\002', ' ', '\003', '(', '\013', '2', '&', '.', 'g', 'o', 'o', 'g', 'l', +'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'M', 'e', 't', 'h', 'o', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', +'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\006', 'm', 'e', 't', 'h', 'o', 'd', '\022', '9', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', +'s', '\030', '\003', ' ', '\001', '(', '\013', '2', '\037', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', +'.', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\"', +'\211', '\002', '\n', '\025', 'M', 'e', 't', 'h', 'o', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', +'\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\035', '\n', '\n', 'i', +'n', 'p', 'u', 't', '_', 't', 'y', 'p', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\t', 'i', 'n', 'p', 'u', 't', 'T', 'y', 'p', +'e', '\022', '\037', '\n', '\013', 'o', 'u', 't', 'p', 'u', 't', '_', 't', 'y', 'p', 'e', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\n', 'o', +'u', 't', 'p', 'u', 't', 'T', 'y', 'p', 'e', '\022', '8', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\004', ' ', '\001', '(', +'\013', '2', '\036', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'M', 'e', 't', 'h', 'o', +'d', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\022', '0', '\n', '\020', 'c', 'l', 'i', 'e', +'n', 't', '_', 's', 't', 'r', 'e', 'a', 'm', 'i', 'n', 'g', '\030', '\005', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', +'R', '\017', 'c', 'l', 'i', 'e', 'n', 't', 'S', 't', 'r', 'e', 'a', 'm', 'i', 'n', 'g', '\022', '0', '\n', '\020', 's', 'e', 'r', 'v', +'e', 'r', '_', 's', 't', 'r', 'e', 'a', 'm', 'i', 'n', 'g', '\030', '\006', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', +'R', '\017', 's', 'e', 'r', 'v', 'e', 'r', 'S', 't', 'r', 'e', 'a', 'm', 'i', 'n', 'g', '\"', '\221', '\t', '\n', '\013', 'F', 'i', 'l', +'e', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '!', '\n', '\014', 'j', 'a', 'v', 'a', '_', 'p', 'a', 'c', 'k', 'a', 'g', 'e', '\030', +'\001', ' ', '\001', '(', '\t', 'R', '\013', 'j', 'a', 'v', 'a', 'P', 'a', 'c', 'k', 'a', 'g', 'e', '\022', '0', '\n', '\024', 'j', 'a', 'v', +'a', '_', 'o', 'u', 't', 'e', 'r', '_', 'c', 'l', 'a', 's', 's', 'n', 'a', 'm', 'e', '\030', '\010', ' ', '\001', '(', '\t', 'R', '\022', +'j', 'a', 'v', 'a', 'O', 'u', 't', 'e', 'r', 'C', 'l', 'a', 's', 's', 'n', 'a', 'm', 'e', '\022', '5', '\n', '\023', 'j', 'a', 'v', +'a', '_', 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', '_', 'f', 'i', 'l', 'e', 's', '\030', '\n', ' ', '\001', '(', '\010', ':', '\005', 'f', +'a', 'l', 's', 'e', 'R', '\021', 'j', 'a', 'v', 'a', 'M', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'F', 'i', 'l', 'e', 's', '\022', 'D', +'\n', '\035', 'j', 'a', 'v', 'a', '_', 'g', 'e', 'n', 'e', 'r', 'a', 't', 'e', '_', 'e', 'q', 'u', 'a', 'l', 's', '_', 'a', 'n', +'d', '_', 'h', 'a', 's', 'h', '\030', '\024', ' ', '\001', '(', '\010', 'B', '\002', '\030', '\001', 'R', '\031', 'j', 'a', 'v', 'a', 'G', 'e', 'n', +'e', 'r', 'a', 't', 'e', 'E', 'q', 'u', 'a', 'l', 's', 'A', 'n', 'd', 'H', 'a', 's', 'h', '\022', ':', '\n', '\026', 'j', 'a', 'v', +'a', '_', 's', 't', 'r', 'i', 'n', 'g', '_', 'c', 'h', 'e', 'c', 'k', '_', 'u', 't', 'f', '8', '\030', '\033', ' ', '\001', '(', '\010', +':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\023', 'j', 'a', 'v', 'a', 'S', 't', 'r', 'i', 'n', 'g', 'C', 'h', 'e', 'c', 'k', 'U', +'t', 'f', '8', '\022', 'S', '\n', '\014', 'o', 'p', 't', 'i', 'm', 'i', 'z', 'e', '_', 'f', 'o', 'r', '\030', '\t', ' ', '\001', '(', '\016', +'2', ')', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'l', 'e', 'O', 'p', +'t', 'i', 'o', 'n', 's', '.', 'O', 'p', 't', 'i', 'm', 'i', 'z', 'e', 'M', 'o', 'd', 'e', ':', '\005', 'S', 'P', 'E', 'E', 'D', +'R', '\013', 'o', 'p', 't', 'i', 'm', 'i', 'z', 'e', 'F', 'o', 'r', '\022', '\035', '\n', '\n', 'g', 'o', '_', 'p', 'a', 'c', 'k', 'a', +'g', 'e', '\030', '\013', ' ', '\001', '(', '\t', 'R', '\t', 'g', 'o', 'P', 'a', 'c', 'k', 'a', 'g', 'e', '\022', '5', '\n', '\023', 'c', 'c', +'_', 'g', 'e', 'n', 'e', 'r', 'i', 'c', '_', 's', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\030', '\020', ' ', '\001', '(', '\010', ':', '\005', +'f', 'a', 'l', 's', 'e', 'R', '\021', 'c', 'c', 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\022', +'9', '\n', '\025', 'j', 'a', 'v', 'a', '_', 'g', 'e', 'n', 'e', 'r', 'i', 'c', '_', 's', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\030', +'\021', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\023', 'j', 'a', 'v', 'a', 'G', 'e', 'n', 'e', 'r', 'i', 'c', +'S', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\022', '5', '\n', '\023', 'p', 'y', '_', 'g', 'e', 'n', 'e', 'r', 'i', 'c', '_', 's', 'e', +'r', 'v', 'i', 'c', 'e', 's', '\030', '\022', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\021', 'p', 'y', 'G', 'e', +'n', 'e', 'r', 'i', 'c', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\022', '7', '\n', '\024', 'p', 'h', 'p', '_', 'g', 'e', 'n', 'e', +'r', 'i', 'c', '_', 's', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\030', '*', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', +'R', '\022', 'p', 'h', 'p', 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\022', '%', '\n', '\n', 'd', +'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '\027', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\n', 'd', +'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', '.', '\n', '\020', 'c', 'c', '_', 'e', 'n', 'a', 'b', 'l', 'e', '_', 'a', 'r', +'e', 'n', 'a', 's', '\030', '\037', ' ', '\001', '(', '\010', ':', '\004', 't', 'r', 'u', 'e', 'R', '\016', 'c', 'c', 'E', 'n', 'a', 'b', 'l', +'e', 'A', 'r', 'e', 'n', 'a', 's', '\022', '*', '\n', '\021', 'o', 'b', 'j', 'c', '_', 'c', 'l', 'a', 's', 's', '_', 'p', 'r', 'e', +'f', 'i', 'x', '\030', '$', ' ', '\001', '(', '\t', 'R', '\017', 'o', 'b', 'j', 'c', 'C', 'l', 'a', 's', 's', 'P', 'r', 'e', 'f', 'i', +'x', '\022', ')', '\n', '\020', 'c', 's', 'h', 'a', 'r', 'p', '_', 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\030', '%', ' ', '\001', +'(', '\t', 'R', '\017', 'c', 's', 'h', 'a', 'r', 'p', 'N', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\022', '!', '\n', '\014', 's', 'w', +'i', 'f', 't', '_', 'p', 'r', 'e', 'f', 'i', 'x', '\030', '\'', ' ', '\001', '(', '\t', 'R', '\013', 's', 'w', 'i', 'f', 't', 'P', 'r', +'e', 'f', 'i', 'x', '\022', '(', '\n', '\020', 'p', 'h', 'p', '_', 'c', 'l', 'a', 's', 's', '_', 'p', 'r', 'e', 'f', 'i', 'x', '\030', +'(', ' ', '\001', '(', '\t', 'R', '\016', 'p', 'h', 'p', 'C', 'l', 'a', 's', 's', 'P', 'r', 'e', 'f', 'i', 'x', '\022', '#', '\n', '\r', +'p', 'h', 'p', '_', 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\030', ')', ' ', '\001', '(', '\t', 'R', '\014', 'p', 'h', 'p', 'N', +'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\022', '4', '\n', '\026', 'p', 'h', 'p', '_', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '_', +'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\030', ',', ' ', '\001', '(', '\t', 'R', '\024', 'p', 'h', 'p', 'M', 'e', 't', 'a', 'd', +'a', 't', 'a', 'N', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\022', '!', '\n', '\014', 'r', 'u', 'b', 'y', '_', 'p', 'a', 'c', 'k', +'a', 'g', 'e', '\030', '-', ' ', '\001', '(', '\t', 'R', '\013', 'r', 'u', 'b', 'y', 'P', 'a', 'c', 'k', 'a', 'g', 'e', '\022', 'X', '\n', +'\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', +'\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', +'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', +'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '\"', ':', '\n', '\014', 'O', 'p', 't', 'i', 'm', 'i', 'z', 'e', 'M', +'o', 'd', 'e', '\022', '\t', '\n', '\005', 'S', 'P', 'E', 'E', 'D', '\020', '\001', '\022', '\r', '\n', '\t', 'C', 'O', 'D', 'E', '_', 'S', 'I', +'Z', 'E', '\020', '\002', '\022', '\020', '\n', '\014', 'L', 'I', 'T', 'E', '_', 'R', 'U', 'N', 'T', 'I', 'M', 'E', '\020', '\003', '*', '\t', '\010', +'\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', 'J', '\004', '\010', '&', '\020', '\'', '\"', '\343', '\002', '\n', '\016', 'M', 'e', 's', 's', 'a', 'g', +'e', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '<', '\n', '\027', 'm', 'e', 's', 's', 'a', 'g', 'e', '_', 's', 'e', 't', '_', 'w', +'i', 'r', 'e', '_', 'f', 'o', 'r', 'm', 'a', 't', '\030', '\001', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\024', +'m', 'e', 's', 's', 'a', 'g', 'e', 'S', 'e', 't', 'W', 'i', 'r', 'e', 'F', 'o', 'r', 'm', 'a', 't', '\022', 'L', '\n', '\037', 'n', +'o', '_', 's', 't', 'a', 'n', 'd', 'a', 'r', 'd', '_', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '_', 'a', 'c', 'c', +'e', 's', 's', 'o', 'r', '\030', '\002', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\034', 'n', 'o', 'S', 't', 'a', +'n', 'd', 'a', 'r', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'A', 'c', 'c', 'e', 's', 's', 'o', 'r', '\022', '%', +'\n', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '\003', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', +'R', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', '\033', '\n', '\t', 'm', 'a', 'p', '_', 'e', 'n', 't', 'r', 'y', +'\030', '\007', ' ', '\001', '(', '\010', 'R', '\010', 'm', 'a', 'p', 'E', 'n', 't', 'r', 'y', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', +'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', +'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', +'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', +'O', 'p', 't', 'i', 'o', 'n', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', 'J', '\004', '\010', '\004', '\020', '\005', 'J', '\004', +'\010', '\005', '\020', '\006', 'J', '\004', '\010', '\006', '\020', '\007', 'J', '\004', '\010', '\010', '\020', '\t', 'J', '\004', '\010', '\t', '\020', '\n', '\"', '\222', '\004', +'\n', '\014', 'F', 'i', 'e', 'l', 'd', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', 'A', '\n', '\005', 'c', 't', 'y', 'p', 'e', '\030', '\001', +' ', '\001', '(', '\016', '2', '#', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', +'e', 'l', 'd', 'O', 'p', 't', 'i', 'o', 'n', 's', '.', 'C', 'T', 'y', 'p', 'e', ':', '\006', 'S', 'T', 'R', 'I', 'N', 'G', 'R', +'\005', 'c', 't', 'y', 'p', 'e', '\022', '\026', '\n', '\006', 'p', 'a', 'c', 'k', 'e', 'd', '\030', '\002', ' ', '\001', '(', '\010', 'R', '\006', 'p', +'a', 'c', 'k', 'e', 'd', '\022', 'G', '\n', '\006', 'j', 's', 't', 'y', 'p', 'e', '\030', '\006', ' ', '\001', '(', '\016', '2', '$', '.', 'g', +'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'O', 'p', 't', 'i', 'o', +'n', 's', '.', 'J', 'S', 'T', 'y', 'p', 'e', ':', '\t', 'J', 'S', '_', 'N', 'O', 'R', 'M', 'A', 'L', 'R', '\006', 'j', 's', 't', +'y', 'p', 'e', '\022', '\031', '\n', '\004', 'l', 'a', 'z', 'y', '\030', '\005', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', +'\004', 'l', 'a', 'z', 'y', '\022', '.', '\n', '\017', 'u', 'n', 'v', 'e', 'r', 'i', 'f', 'i', 'e', 'd', '_', 'l', 'a', 'z', 'y', '\030', +'\017', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\016', 'u', 'n', 'v', 'e', 'r', 'i', 'f', 'i', 'e', 'd', 'L', +'a', 'z', 'y', '\022', '%', '\n', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '\003', ' ', '\001', '(', '\010', ':', '\005', +'f', 'a', 'l', 's', 'e', 'R', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', '\031', '\n', '\004', 'w', 'e', 'a', 'k', +'\030', '\n', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\004', 'w', 'e', 'a', 'k', '\022', 'X', '\n', '\024', 'u', 'n', +'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', +'2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', +'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', +'t', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '\"', '/', '\n', '\005', 'C', 'T', 'y', 'p', 'e', '\022', '\n', '\n', '\006', 'S', 'T', 'R', +'I', 'N', 'G', '\020', '\000', '\022', '\010', '\n', '\004', 'C', 'O', 'R', 'D', '\020', '\001', '\022', '\020', '\n', '\014', 'S', 'T', 'R', 'I', 'N', 'G', +'_', 'P', 'I', 'E', 'C', 'E', '\020', '\002', '\"', '5', '\n', '\006', 'J', 'S', 'T', 'y', 'p', 'e', '\022', '\r', '\n', '\t', 'J', 'S', '_', +'N', 'O', 'R', 'M', 'A', 'L', '\020', '\000', '\022', '\r', '\n', '\t', 'J', 'S', '_', 'S', 'T', 'R', 'I', 'N', 'G', '\020', '\001', '\022', '\r', +'\n', '\t', 'J', 'S', '_', 'N', 'U', 'M', 'B', 'E', 'R', '\020', '\002', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', 'J', +'\004', '\010', '\004', '\020', '\005', '\"', 's', '\n', '\014', 'O', 'n', 'e', 'o', 'f', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', 'X', '\n', '\024', +'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', +'(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', +'t', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', +'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', '\"', '\300', '\001', +'\n', '\013', 'E', 'n', 'u', 'm', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '\037', '\n', '\013', 'a', 'l', 'l', 'o', 'w', '_', 'a', 'l', +'i', 'a', 's', '\030', '\002', ' ', '\001', '(', '\010', 'R', '\n', 'a', 'l', 'l', 'o', 'w', 'A', 'l', 'i', 'a', 's', '\022', '%', '\n', '\n', +'d', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '\003', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\n', +'d', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', +'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', +'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', +'t', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', +'*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', 'J', '\004', '\010', '\005', '\020', '\006', '\"', '\236', '\001', '\n', '\020', 'E', 'n', 'u', +'m', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '%', '\n', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', +'e', 'd', '\030', '\001', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', +'e', 'd', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', +'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', +'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', +'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', +'\200', '\200', '\002', '\"', '\234', '\001', '\n', '\016', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '%', '\n', +'\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '!', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', +'\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', +'t', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', +'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', +'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', +'n', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', '\"', '\340', '\002', '\n', '\r', 'M', 'e', 't', 'h', 'o', 'd', 'O', 'p', +'t', 'i', 'o', 'n', 's', '\022', '%', '\n', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '!', ' ', '\001', '(', '\010', +':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', 'q', '\n', '\021', 'i', 'd', +'e', 'm', 'p', 'o', 't', 'e', 'n', 'c', 'y', '_', 'l', 'e', 'v', 'e', 'l', '\030', '\"', ' ', '\001', '(', '\016', '2', '/', '.', 'g', +'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'M', 'e', 't', 'h', 'o', 'd', 'O', 'p', 't', 'i', +'o', 'n', 's', '.', 'I', 'd', 'e', 'm', 'p', 'o', 't', 'e', 'n', 'c', 'y', 'L', 'e', 'v', 'e', 'l', ':', '\023', 'I', 'D', 'E', +'M', 'P', 'O', 'T', 'E', 'N', 'C', 'Y', '_', 'U', 'N', 'K', 'N', 'O', 'W', 'N', 'R', '\020', 'i', 'd', 'e', 'm', 'p', 'o', 't', +'e', 'n', 'c', 'y', 'L', 'e', 'v', 'e', 'l', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', +'d', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', +'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', +'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '\"', +'P', '\n', '\020', 'I', 'd', 'e', 'm', 'p', 'o', 't', 'e', 'n', 'c', 'y', 'L', 'e', 'v', 'e', 'l', '\022', '\027', '\n', '\023', 'I', 'D', +'E', 'M', 'P', 'O', 'T', 'E', 'N', 'C', 'Y', '_', 'U', 'N', 'K', 'N', 'O', 'W', 'N', '\020', '\000', '\022', '\023', '\n', '\017', 'N', 'O', +'_', 'S', 'I', 'D', 'E', '_', 'E', 'F', 'F', 'E', 'C', 'T', 'S', '\020', '\001', '\022', '\016', '\n', '\n', 'I', 'D', 'E', 'M', 'P', 'O', +'T', 'E', 'N', 'T', '\020', '\002', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', '\"', '\232', '\003', '\n', '\023', 'U', 'n', 'i', +'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '\022', 'A', '\n', '\004', 'n', 'a', 'm', 'e', '\030', +'\002', ' ', '\003', '(', '\013', '2', '-', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', +'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '.', 'N', 'a', 'm', 'e', 'P', 'a', +'r', 't', 'R', '\004', 'n', 'a', 'm', 'e', '\022', ')', '\n', '\020', 'i', 'd', 'e', 'n', 't', 'i', 'f', 'i', 'e', 'r', '_', 'v', 'a', +'l', 'u', 'e', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\017', 'i', 'd', 'e', 'n', 't', 'i', 'f', 'i', 'e', 'r', 'V', 'a', 'l', 'u', +'e', '\022', ',', '\n', '\022', 'p', 'o', 's', 'i', 't', 'i', 'v', 'e', '_', 'i', 'n', 't', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\004', +' ', '\001', '(', '\004', 'R', '\020', 'p', 'o', 's', 'i', 't', 'i', 'v', 'e', 'I', 'n', 't', 'V', 'a', 'l', 'u', 'e', '\022', ',', '\n', +'\022', 'n', 'e', 'g', 'a', 't', 'i', 'v', 'e', '_', 'i', 'n', 't', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\005', ' ', '\001', '(', '\003', +'R', '\020', 'n', 'e', 'g', 'a', 't', 'i', 'v', 'e', 'I', 'n', 't', 'V', 'a', 'l', 'u', 'e', '\022', '!', '\n', '\014', 'd', 'o', 'u', +'b', 'l', 'e', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\006', ' ', '\001', '(', '\001', 'R', '\013', 'd', 'o', 'u', 'b', 'l', 'e', 'V', 'a', +'l', 'u', 'e', '\022', '!', '\n', '\014', 's', 't', 'r', 'i', 'n', 'g', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\007', ' ', '\001', '(', '\014', +'R', '\013', 's', 't', 'r', 'i', 'n', 'g', 'V', 'a', 'l', 'u', 'e', '\022', '\'', '\n', '\017', 'a', 'g', 'g', 'r', 'e', 'g', 'a', 't', +'e', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\010', ' ', '\001', '(', '\t', 'R', '\016', 'a', 'g', 'g', 'r', 'e', 'g', 'a', 't', 'e', 'V', +'a', 'l', 'u', 'e', '\032', 'J', '\n', '\010', 'N', 'a', 'm', 'e', 'P', 'a', 'r', 't', '\022', '\033', '\n', '\t', 'n', 'a', 'm', 'e', '_', +'p', 'a', 'r', 't', '\030', '\001', ' ', '\002', '(', '\t', 'R', '\010', 'n', 'a', 'm', 'e', 'P', 'a', 'r', 't', '\022', '!', '\n', '\014', 'i', +'s', '_', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\030', '\002', ' ', '\002', '(', '\010', 'R', '\013', 'i', 's', 'E', 'x', 't', 'e', +'n', 's', 'i', 'o', 'n', '\"', '\247', '\002', '\n', '\016', 'S', 'o', 'u', 'r', 'c', 'e', 'C', 'o', 'd', 'e', 'I', 'n', 'f', 'o', '\022', +'D', '\n', '\010', 'l', 'o', 'c', 'a', 't', 'i', 'o', 'n', '\030', '\001', ' ', '\003', '(', '\013', '2', '(', '.', 'g', 'o', 'o', 'g', 'l', +'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 'o', 'u', 'r', 'c', 'e', 'C', 'o', 'd', 'e', 'I', 'n', 'f', 'o', +'.', 'L', 'o', 'c', 'a', 't', 'i', 'o', 'n', 'R', '\010', 'l', 'o', 'c', 'a', 't', 'i', 'o', 'n', '\032', '\316', '\001', '\n', '\010', 'L', +'o', 'c', 'a', 't', 'i', 'o', 'n', '\022', '\026', '\n', '\004', 'p', 'a', 't', 'h', '\030', '\001', ' ', '\003', '(', '\005', 'B', '\002', '\020', '\001', +'R', '\004', 'p', 'a', 't', 'h', '\022', '\026', '\n', '\004', 's', 'p', 'a', 'n', '\030', '\002', ' ', '\003', '(', '\005', 'B', '\002', '\020', '\001', 'R', +'\004', 's', 'p', 'a', 'n', '\022', ')', '\n', '\020', 'l', 'e', 'a', 'd', 'i', 'n', 'g', '_', 'c', 'o', 'm', 'm', 'e', 'n', 't', 's', +'\030', '\003', ' ', '\001', '(', '\t', 'R', '\017', 'l', 'e', 'a', 'd', 'i', 'n', 'g', 'C', 'o', 'm', 'm', 'e', 'n', 't', 's', '\022', '+', +'\n', '\021', 't', 'r', 'a', 'i', 'l', 'i', 'n', 'g', '_', 'c', 'o', 'm', 'm', 'e', 'n', 't', 's', '\030', '\004', ' ', '\001', '(', '\t', +'R', '\020', 't', 'r', 'a', 'i', 'l', 'i', 'n', 'g', 'C', 'o', 'm', 'm', 'e', 'n', 't', 's', '\022', ':', '\n', '\031', 'l', 'e', 'a', +'d', 'i', 'n', 'g', '_', 'd', 'e', 't', 'a', 'c', 'h', 'e', 'd', '_', 'c', 'o', 'm', 'm', 'e', 'n', 't', 's', '\030', '\006', ' ', +'\003', '(', '\t', 'R', '\027', 'l', 'e', 'a', 'd', 'i', 'n', 'g', 'D', 'e', 't', 'a', 'c', 'h', 'e', 'd', 'C', 'o', 'm', 'm', 'e', +'n', 't', 's', '\"', '\320', '\002', '\n', '\021', 'G', 'e', 'n', 'e', 'r', 'a', 't', 'e', 'd', 'C', 'o', 'd', 'e', 'I', 'n', 'f', 'o', +'\022', 'M', '\n', '\n', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', '\030', '\001', ' ', '\003', '(', '\013', '2', '-', '.', 'g', 'o', +'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'G', 'e', 'n', 'e', 'r', 'a', 't', 'e', 'd', 'C', 'o', +'d', 'e', 'I', 'n', 'f', 'o', '.', 'A', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 'R', '\n', 'a', 'n', 'n', 'o', 't', 'a', +'t', 'i', 'o', 'n', '\032', '\353', '\001', '\n', '\n', 'A', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', '\022', '\026', '\n', '\004', 'p', 'a', +'t', 'h', '\030', '\001', ' ', '\003', '(', '\005', 'B', '\002', '\020', '\001', 'R', '\004', 'p', 'a', 't', 'h', '\022', '\037', '\n', '\013', 's', 'o', 'u', +'r', 'c', 'e', '_', 'f', 'i', 'l', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\n', 's', 'o', 'u', 'r', 'c', 'e', 'F', 'i', 'l', +'e', '\022', '\024', '\n', '\005', 'b', 'e', 'g', 'i', 'n', '\030', '\003', ' ', '\001', '(', '\005', 'R', '\005', 'b', 'e', 'g', 'i', 'n', '\022', '\020', +'\n', '\003', 'e', 'n', 'd', '\030', '\004', ' ', '\001', '(', '\005', 'R', '\003', 'e', 'n', 'd', '\022', 'R', '\n', '\010', 's', 'e', 'm', 'a', 'n', +'t', 'i', 'c', '\030', '\005', ' ', '\001', '(', '\016', '2', '6', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', +'u', 'f', '.', 'G', 'e', 'n', 'e', 'r', 'a', 't', 'e', 'd', 'C', 'o', 'd', 'e', 'I', 'n', 'f', 'o', '.', 'A', 'n', 'n', 'o', +'t', 'a', 't', 'i', 'o', 'n', '.', 'S', 'e', 'm', 'a', 'n', 't', 'i', 'c', 'R', '\010', 's', 'e', 'm', 'a', 'n', 't', 'i', 'c', +'\"', '(', '\n', '\010', 'S', 'e', 'm', 'a', 'n', 't', 'i', 'c', '\022', '\010', '\n', '\004', 'N', 'O', 'N', 'E', '\020', '\000', '\022', '\007', '\n', +'\003', 'S', 'E', 'T', '\020', '\001', '\022', '\t', '\n', '\005', 'A', 'L', 'I', 'A', 'S', '\020', '\002', 'B', '~', '\n', '\023', 'c', 'o', 'm', '.', +'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', 'B', '\020', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', +'o', 'r', 'P', 'r', 'o', 't', 'o', 's', 'H', '\001', 'Z', '-', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'g', 'o', 'l', 'a', 'n', 'g', +'.', 'o', 'r', 'g', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 't', 'y', 'p', 'e', 's', '/', 'd', 'e', 's', 'c', 'r', +'i', 'p', 't', 'o', 'r', 'p', 'b', '\370', '\001', '\001', '\242', '\002', '\003', 'G', 'P', 'B', '\252', '\002', '\032', 'G', 'o', 'o', 'g', 'l', 'e', +'.', 'P', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'R', 'e', 'f', 'l', 'e', 'c', 't', 'i', 'o', 'n', +}; + +static _upb_DefPool_Init *deps[1] = { + NULL +}; + +_upb_DefPool_Init google_protobuf_descriptor_proto_upbdefinit = { + deps, + &google_protobuf_descriptor_proto_upb_file_layout, + "google/protobuf/descriptor.proto", + UPB_STRINGVIEW_INIT(descriptor, 7820) +}; + + + +// Must be last. + +struct upb_ExtensionRegistry { + upb_Arena* arena; + upb_strtable exts; /* Key is upb_MiniTable* concatenated with fieldnum. */ +}; + +#define EXTREG_KEY_SIZE (sizeof(upb_MiniTable*) + sizeof(uint32_t)) + +static void extreg_key(char* buf, const upb_MiniTable* l, uint32_t fieldnum) { + memcpy(buf, &l, sizeof(l)); + memcpy(buf + sizeof(l), &fieldnum, sizeof(fieldnum)); +} + +upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena) { + upb_ExtensionRegistry* r = upb_Arena_Malloc(arena, sizeof(*r)); + if (!r) return NULL; + r->arena = arena; + if (!upb_strtable_init(&r->exts, 8, arena)) return NULL; + return r; +} + +bool _upb_extreg_add(upb_ExtensionRegistry* r, + const upb_MiniTable_Extension** e, size_t count) { + char buf[EXTREG_KEY_SIZE]; + const upb_MiniTable_Extension** start = e; + const upb_MiniTable_Extension** end = UPB_PTRADD(e, count); + for (; e < end; e++) { + // TODO: we should gracefully handle the case where this already exists. + // Right now we're only checking for out of memory. + const upb_MiniTable_Extension* ext = *e; + extreg_key(buf, ext->extendee, ext->field.number); + if (!upb_strtable_insert(&r->exts, buf, EXTREG_KEY_SIZE, + upb_value_constptr(ext), r->arena)) { + goto failure; + } + } + return true; + +failure: + /* Back out the entries previously added. */ + for (end = e, e = start; e < end; e++) { + const upb_MiniTable_Extension* ext = *e; + extreg_key(buf, ext->extendee, ext->field.number); + upb_strtable_remove2(&r->exts, buf, EXTREG_KEY_SIZE, NULL); + } + return false; +} + +const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r, + const upb_MiniTable* l, + uint32_t num) { + char buf[EXTREG_KEY_SIZE]; + upb_value v; + extreg_key(buf, l, num); + if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, &v)) { + return upb_value_getconstptr(v); + } else { + return NULL; + } +} + +// Fast decoder: ~3x the speed of decode.c, but requires x86-64/ARM64. +// Also the table size grows by 2x. +// +// Could potentially be ported to other 64-bit archs that pass at least six +// arguments in registers and have 8 unused high bits in pointers. +// +// The overall design is to create specialized functions for every possible +// field type (eg. oneof boolean field with a 1 byte tag) and then dispatch +// to the specialized function as quickly as possible. + + + +// Must be last. + +#if UPB_FASTTABLE + +// The standard set of arguments passed to each parsing function. +// Thanks to x86-64 calling conventions, these will stay in registers. +#define UPB_PARSE_PARAMS \ + upb_Decoder *d, const char *ptr, upb_Message *msg, intptr_t table, \ + uint64_t hasbits, uint64_t data + +#define UPB_PARSE_ARGS d, ptr, msg, table, hasbits, data + +#define RETURN_GENERIC(m) \ + /* Uncomment either of these for debugging purposes. */ \ + /* fprintf(stderr, m); */ \ + /*__builtin_trap(); */ \ + return _upb_FastDecoder_DecodeGeneric(d, ptr, msg, table, hasbits, 0); + +typedef enum { + CARD_s = 0, /* Singular (optional, non-repeated) */ + CARD_o = 1, /* Oneof */ + CARD_r = 2, /* Repeated */ + CARD_p = 3 /* Packed Repeated */ +} upb_card; + +UPB_NOINLINE +static const char* fastdecode_isdonefallback(UPB_PARSE_PARAMS) { + int overrun = data; + int status; + ptr = _upb_Decoder_IsDoneFallbackInline(d, ptr, overrun, &status); + if (ptr == NULL) _upb_FastDecoder_ErrorJmp(d, status); + data = _upb_FastDecoder_LoadTag(ptr); + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); +} + +UPB_FORCEINLINE +static const char* fastdecode_dispatch(UPB_PARSE_PARAMS) { + if (UPB_UNLIKELY(ptr >= d->limit_ptr)) { + int overrun = ptr - d->end; + if (UPB_LIKELY(overrun == d->limit)) { + // Parse is finished. + *(uint32_t*)msg |= hasbits; // Sync hasbits. + const upb_MiniTable* l = decode_totablep(table); + return UPB_UNLIKELY(l->required_count) + ? _upb_Decoder_CheckRequired(d, ptr, msg, l) + : ptr; + } else { + data = overrun; + UPB_MUSTTAIL return fastdecode_isdonefallback(UPB_PARSE_ARGS); + } + } + + // Read two bytes of tag data (for a one-byte tag, the high byte is junk). + data = _upb_FastDecoder_LoadTag(ptr); + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); +} + +UPB_FORCEINLINE +static bool fastdecode_checktag(uint16_t data, int tagbytes) { + if (tagbytes == 1) { + return (data & 0xff) == 0; + } else { + return data == 0; + } +} + +UPB_FORCEINLINE +static const char* fastdecode_longsize(const char* ptr, int* size) { + int i; + UPB_ASSERT(*size & 0x80); + *size &= 0xff; + for (i = 0; i < 3; i++) { + ptr++; + size_t byte = (uint8_t)ptr[-1]; + *size += (byte - 1) << (7 + 7 * i); + if (UPB_LIKELY((byte & 0x80) == 0)) return ptr; + } + ptr++; + size_t byte = (uint8_t)ptr[-1]; + // len is limited by 2gb not 4gb, hence 8 and not 16 as normally expected + // for a 32 bit varint. + if (UPB_UNLIKELY(byte >= 8)) return NULL; + *size += (byte - 1) << 28; + return ptr; +} + +UPB_FORCEINLINE +static bool fastdecode_boundscheck(const char* ptr, size_t len, + const char* end) { + uintptr_t uptr = (uintptr_t)ptr; + uintptr_t uend = (uintptr_t)end + 16; + uintptr_t res = uptr + len; + return res < uptr || res > uend; +} + +UPB_FORCEINLINE +static bool fastdecode_boundscheck2(const char* ptr, size_t len, + const char* end) { + // This is one extra branch compared to the more normal: + // return (size_t)(end - ptr) < size; + // However it is one less computation if we are just about to use "ptr + len": + // https://godbolt.org/z/35YGPz + // In microbenchmarks this shows an overall 4% improvement. + uintptr_t uptr = (uintptr_t)ptr; + uintptr_t uend = (uintptr_t)end; + uintptr_t res = uptr + len; + return res < uptr || res > uend; +} + +typedef const char* fastdecode_delimfunc(upb_Decoder* d, const char* ptr, + void* ctx); + +UPB_FORCEINLINE +static const char* fastdecode_delimited(upb_Decoder* d, const char* ptr, + fastdecode_delimfunc* func, void* ctx) { + ptr++; + int len = (int8_t)ptr[-1]; + if (fastdecode_boundscheck2(ptr, len, d->limit_ptr)) { + // Slow case: Sub-message is >=128 bytes and/or exceeds the current buffer. + // If it exceeds the buffer limit, limit/limit_ptr will change during + // sub-message parsing, so we need to preserve delta, not limit. + if (UPB_UNLIKELY(len & 0x80)) { + // Size varint >1 byte (length >= 128). + ptr = fastdecode_longsize(ptr, &len); + if (!ptr) { + // Corrupt wire format: size exceeded INT_MAX. + return NULL; + } + } + if (ptr - d->end + (int)len > d->limit) { + // Corrupt wire format: invalid limit. + return NULL; + } + int delta = _upb_Decoder_PushLimit(d, ptr, len); + ptr = func(d, ptr, ctx); + _upb_Decoder_PopLimit(d, ptr, delta); + } else { + // Fast case: Sub-message is <128 bytes and fits in the current buffer. + // This means we can preserve limit/limit_ptr verbatim. + const char* saved_limit_ptr = d->limit_ptr; + int saved_limit = d->limit; + d->limit_ptr = ptr + len; + d->limit = d->limit_ptr - d->end; + UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); + ptr = func(d, ptr, ctx); + d->limit_ptr = saved_limit_ptr; + d->limit = saved_limit; + UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); + } + return ptr; +} + +/* singular, oneof, repeated field handling ***********************************/ + +typedef struct { + upb_Array* arr; + void* end; +} fastdecode_arr; + +typedef enum { + FD_NEXT_ATLIMIT, + FD_NEXT_SAMEFIELD, + FD_NEXT_OTHERFIELD +} fastdecode_next; + +typedef struct { + void* dst; + fastdecode_next next; + uint32_t tag; +} fastdecode_nextret; + +UPB_FORCEINLINE +static void* fastdecode_resizearr(upb_Decoder* d, void* dst, + fastdecode_arr* farr, int valbytes) { + if (UPB_UNLIKELY(dst == farr->end)) { + size_t old_size = farr->arr->capacity; + size_t old_bytes = old_size * valbytes; + size_t new_size = old_size * 2; + size_t new_bytes = new_size * valbytes; + char* old_ptr = _upb_array_ptr(farr->arr); + char* new_ptr = upb_Arena_Realloc(&d->arena, old_ptr, old_bytes, new_bytes); + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); + farr->arr->capacity = new_size; + farr->arr->data = _upb_array_tagptr(new_ptr, elem_size_lg2); + dst = (void*)(new_ptr + (old_size * valbytes)); + farr->end = (void*)(new_ptr + (new_size * valbytes)); + } + return dst; +} + +UPB_FORCEINLINE +static bool fastdecode_tagmatch(uint32_t tag, uint64_t data, int tagbytes) { + if (tagbytes == 1) { + return (uint8_t)tag == (uint8_t)data; + } else { + return (uint16_t)tag == (uint16_t)data; + } +} + +UPB_FORCEINLINE +static void fastdecode_commitarr(void* dst, fastdecode_arr* farr, + int valbytes) { + farr->arr->size = + (size_t)((char*)dst - (char*)_upb_array_ptr(farr->arr)) / valbytes; +} + +UPB_FORCEINLINE +static fastdecode_nextret fastdecode_nextrepeated(upb_Decoder* d, void* dst, + const char** ptr, + fastdecode_arr* farr, + uint64_t data, int tagbytes, + int valbytes) { + fastdecode_nextret ret; + dst = (char*)dst + valbytes; + + if (UPB_LIKELY(!_upb_Decoder_IsDone(d, ptr))) { + ret.tag = _upb_FastDecoder_LoadTag(*ptr); + if (fastdecode_tagmatch(ret.tag, data, tagbytes)) { + ret.next = FD_NEXT_SAMEFIELD; + } else { + fastdecode_commitarr(dst, farr, valbytes); + ret.next = FD_NEXT_OTHERFIELD; + } + } else { + fastdecode_commitarr(dst, farr, valbytes); + ret.next = FD_NEXT_ATLIMIT; + } + + ret.dst = dst; + return ret; +} + +UPB_FORCEINLINE +static void* fastdecode_fieldmem(upb_Message* msg, uint64_t data) { + size_t ofs = data >> 48; + return (char*)msg + ofs; +} + +UPB_FORCEINLINE +static void* fastdecode_getfield(upb_Decoder* d, const char* ptr, + upb_Message* msg, uint64_t* data, + uint64_t* hasbits, fastdecode_arr* farr, + int valbytes, upb_card card) { + switch (card) { + case CARD_s: { + uint8_t hasbit_index = *data >> 24; + // Set hasbit and return pointer to scalar field. + *hasbits |= 1ull << hasbit_index; + return fastdecode_fieldmem(msg, *data); + } + case CARD_o: { + uint16_t case_ofs = *data >> 32; + uint32_t* oneof_case = UPB_PTR_AT(msg, case_ofs, uint32_t); + uint8_t field_number = *data >> 24; + *oneof_case = field_number; + return fastdecode_fieldmem(msg, *data); + } + case CARD_r: { + // Get pointer to upb_Array and allocate/expand if necessary. + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); + upb_Array** arr_p = fastdecode_fieldmem(msg, *data); + char* begin; + *(uint32_t*)msg |= *hasbits; + *hasbits = 0; + if (UPB_LIKELY(!*arr_p)) { + farr->arr = _upb_Array_New(&d->arena, 8, elem_size_lg2); + *arr_p = farr->arr; + } else { + farr->arr = *arr_p; + } + begin = _upb_array_ptr(farr->arr); + farr->end = begin + (farr->arr->capacity * valbytes); + *data = _upb_FastDecoder_LoadTag(ptr); + return begin + (farr->arr->size * valbytes); + } + default: + UPB_UNREACHABLE(); + } +} + +UPB_FORCEINLINE +static bool fastdecode_flippacked(uint64_t* data, int tagbytes) { + *data ^= (0x2 ^ 0x0); // Patch data to match packed wiretype. + return fastdecode_checktag(*data, tagbytes); +} + +#define FASTDECODE_CHECKPACKED(tagbytes, card, func) \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) { \ + UPB_MUSTTAIL return func(UPB_PARSE_ARGS); \ + } \ + RETURN_GENERIC("packed check tag mismatch\n"); \ + } + +/* varint fields **************************************************************/ + +UPB_FORCEINLINE +static uint64_t fastdecode_munge(uint64_t val, int valbytes, bool zigzag) { + if (valbytes == 1) { + return val != 0; + } else if (zigzag) { + if (valbytes == 4) { + uint32_t n = val; + return (n >> 1) ^ -(int32_t)(n & 1); + } else if (valbytes == 8) { + return (val >> 1) ^ -(int64_t)(val & 1); + } + UPB_UNREACHABLE(); + } + return val; +} + +UPB_FORCEINLINE +static const char* fastdecode_varint64(const char* ptr, uint64_t* val) { + ptr++; + *val = (uint8_t)ptr[-1]; + if (UPB_UNLIKELY(*val & 0x80)) { + int i; + for (i = 0; i < 8; i++) { + ptr++; + uint64_t byte = (uint8_t)ptr[-1]; + *val += (byte - 1) << (7 + 7 * i); + if (UPB_LIKELY((byte & 0x80) == 0)) goto done; + } + ptr++; + uint64_t byte = (uint8_t)ptr[-1]; + if (byte > 1) { + return NULL; + } + *val += (byte - 1) << 63; + } +done: + UPB_ASSUME(ptr != NULL); + return ptr; +} + +#define FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, packed) \ + uint64_t val; \ + void* dst; \ + fastdecode_arr farr; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, card, packed); \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ + card); \ + if (card == CARD_r) { \ + if (UPB_UNLIKELY(!dst)) { \ + RETURN_GENERIC("need array resize\n"); \ + } \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_varint64(ptr, &val); \ + if (ptr == NULL) _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + val = fastdecode_munge(val, valbytes, zigzag); \ + memcpy(dst, &val, valbytes); \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, valbytes); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +typedef struct { + uint8_t valbytes; + bool zigzag; + void* dst; + fastdecode_arr farr; +} fastdecode_varintdata; + +UPB_FORCEINLINE +static const char* fastdecode_topackedvarint(upb_Decoder* d, const char* ptr, + void* ctx) { + fastdecode_varintdata* data = ctx; + void* dst = data->dst; + uint64_t val; + + while (!_upb_Decoder_IsDone(d, &ptr)) { + dst = fastdecode_resizearr(d, dst, &data->farr, data->valbytes); + ptr = fastdecode_varint64(ptr, &val); + if (ptr == NULL) return NULL; + val = fastdecode_munge(val, data->valbytes, data->zigzag); + memcpy(dst, &val, data->valbytes); + dst = (char*)dst + data->valbytes; + } + + fastdecode_commitarr(dst, &data->farr, data->valbytes); + return ptr; +} + +#define FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, zigzag, unpacked) \ + fastdecode_varintdata ctx = {valbytes, zigzag}; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked); \ + \ + ctx.dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &ctx.farr, \ + valbytes, CARD_r); \ + if (UPB_UNLIKELY(!ctx.dst)) { \ + RETURN_GENERIC("need array resize\n"); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_delimited(d, ptr, &fastdecode_topackedvarint, &ctx); \ + \ + if (UPB_UNLIKELY(ptr == NULL)) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(d, ptr, msg, table, hasbits, 0); + +#define FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, unpacked, packed) \ + if (card == CARD_p) { \ + FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, zigzag, unpacked); \ + } else { \ + FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, packed); \ + } + +#define z_ZZ true +#define b_ZZ false +#define v_ZZ false + +/* Generate all combinations: + * {s,o,r,p} x {b1,v4,z4,v8,z8} x {1bt,2bt} */ + +#define F(card, type, valbytes, tagbytes) \ + UPB_NOINLINE \ + const char* upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ + CARD_##card, type##_ZZ, \ + upb_pr##type##valbytes##_##tagbytes##bt, \ + upb_pp##type##valbytes##_##tagbytes##bt); \ + } + +#define TYPES(card, tagbytes) \ + F(card, b, 1, tagbytes) \ + F(card, v, 4, tagbytes) \ + F(card, v, 8, tagbytes) \ + F(card, z, 4, tagbytes) \ + F(card, z, 8, tagbytes) + +#define TAGBYTES(card) \ + TYPES(card, 1) \ + TYPES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) +TAGBYTES(p) + +#undef z_ZZ +#undef b_ZZ +#undef v_ZZ +#undef o_ONEOF +#undef s_ONEOF +#undef r_ONEOF +#undef F +#undef TYPES +#undef TAGBYTES +#undef FASTDECODE_UNPACKEDVARINT +#undef FASTDECODE_PACKEDVARINT +#undef FASTDECODE_VARINT + +/* fixed fields ***************************************************************/ + +#define FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, packed) \ + void* dst; \ + fastdecode_arr farr; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, card, packed) \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ + card); \ + if (card == CARD_r) { \ + if (UPB_UNLIKELY(!dst)) { \ + RETURN_GENERIC("couldn't allocate array in arena\n"); \ + } \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ + } \ + \ + ptr += tagbytes; \ + memcpy(dst, ptr, valbytes); \ + ptr += valbytes; \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, valbytes); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +#define FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, unpacked) \ + FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked) \ + \ + ptr += tagbytes; \ + int size = (uint8_t)ptr[0]; \ + ptr++; \ + if (size & 0x80) { \ + ptr = fastdecode_longsize(ptr, &size); \ + } \ + \ + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr) || \ + (size % valbytes) != 0)) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + upb_Array** arr_p = fastdecode_fieldmem(msg, data); \ + upb_Array* arr = *arr_p; \ + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); \ + int elems = size / valbytes; \ + \ + if (UPB_LIKELY(!arr)) { \ + *arr_p = arr = _upb_Array_New(&d->arena, elems, elem_size_lg2); \ + if (!arr) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + } \ + } else { \ + _upb_Array_Resize(arr, elems, &d->arena); \ + } \ + \ + char* dst = _upb_array_ptr(arr); \ + memcpy(dst, ptr, size); \ + arr->size = elems; \ + \ + ptr += size; \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +#define FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, unpacked, packed) \ + if (card == CARD_p) { \ + FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, unpacked); \ + } else { \ + FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, packed); \ + } + +/* Generate all combinations: + * {s,o,r,p} x {f4,f8} x {1bt,2bt} */ + +#define F(card, valbytes, tagbytes) \ + UPB_NOINLINE \ + const char* upb_p##card##f##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ + CARD_##card, upb_ppf##valbytes##_##tagbytes##bt, \ + upb_prf##valbytes##_##tagbytes##bt); \ + } + +#define TYPES(card, tagbytes) \ + F(card, 4, tagbytes) \ + F(card, 8, tagbytes) + +#define TAGBYTES(card) \ + TYPES(card, 1) \ + TYPES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) +TAGBYTES(p) + +#undef F +#undef TYPES +#undef TAGBYTES +#undef FASTDECODE_UNPACKEDFIXED +#undef FASTDECODE_PACKEDFIXED + +/* string fields **************************************************************/ + +typedef const char* fastdecode_copystr_func(struct upb_Decoder* d, + const char* ptr, upb_Message* msg, + const upb_MiniTable* table, + uint64_t hasbits, + upb_StringView* dst); + +UPB_NOINLINE +static const char* fastdecode_verifyutf8(upb_Decoder* d, const char* ptr, + upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t data) { + upb_StringView* dst = (upb_StringView*)data; + if (!_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_BadUtf8); + } + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +} + +#define FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, validate_utf8) \ + int size = (uint8_t)ptr[0]; /* Could plumb through hasbits. */ \ + ptr++; \ + if (size & 0x80) { \ + ptr = fastdecode_longsize(ptr, &size); \ + } \ + \ + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr))) { \ + dst->size = 0; \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + if (d->options & kUpb_DecodeOption_AliasString) { \ + dst->data = ptr; \ + dst->size = size; \ + } else { \ + char* data = upb_Arena_Malloc(&d->arena, size); \ + if (!data) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); \ + } \ + memcpy(data, ptr, size); \ + dst->data = data; \ + dst->size = size; \ + } \ + \ + ptr += size; \ + if (validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } else { \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ + } + +UPB_NOINLINE +static const char* fastdecode_longstring_utf8(struct upb_Decoder* d, + const char* ptr, upb_Message* msg, + intptr_t table, uint64_t hasbits, + uint64_t data) { + upb_StringView* dst = (upb_StringView*)data; + FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, true); +} + +UPB_NOINLINE +static const char* fastdecode_longstring_noutf8( + struct upb_Decoder* d, const char* ptr, upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t data) { + upb_StringView* dst = (upb_StringView*)data; + FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, false); +} + +UPB_FORCEINLINE +static void fastdecode_docopy(upb_Decoder* d, const char* ptr, uint32_t size, + int copy, char* data, upb_StringView* dst) { + d->arena.head.ptr += copy; + dst->data = data; + UPB_UNPOISON_MEMORY_REGION(data, copy); + memcpy(data, ptr, copy); + UPB_POISON_MEMORY_REGION(data + size, copy - size); +} + +#define FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + card, validate_utf8) \ + upb_StringView* dst; \ + fastdecode_arr farr; \ + int64_t size; \ + size_t arena_has; \ + size_t common_has; \ + char* buf; \ + \ + UPB_ASSERT((d->options & kUpb_DecodeOption_AliasString) == 0); \ + UPB_ASSERT(fastdecode_checktag(data, tagbytes)); \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_StringView), card); \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView)); \ + } \ + \ + size = (uint8_t)ptr[tagbytes]; \ + ptr += tagbytes + 1; \ + dst->size = size; \ + \ + buf = d->arena.head.ptr; \ + arena_has = _upb_ArenaHas(&d->arena); \ + common_has = UPB_MIN(arena_has, (d->end - ptr) + 16); \ + \ + if (UPB_LIKELY(size <= 15 - tagbytes)) { \ + if (arena_has < 16) goto longstr; \ + d->arena.head.ptr += 16; \ + memcpy(buf, ptr - tagbytes - 1, 16); \ + dst->data = buf + tagbytes + 1; \ + } else if (UPB_LIKELY(size <= 32)) { \ + if (UPB_UNLIKELY(common_has < 32)) goto longstr; \ + fastdecode_docopy(d, ptr, size, 32, buf, dst); \ + } else if (UPB_LIKELY(size <= 64)) { \ + if (UPB_UNLIKELY(common_has < 64)) goto longstr; \ + fastdecode_docopy(d, ptr, size, 64, buf, dst); \ + } else if (UPB_LIKELY(size < 128)) { \ + if (UPB_UNLIKELY(common_has < 128)) goto longstr; \ + fastdecode_docopy(d, ptr, size, 128, buf, dst); \ + } else { \ + goto longstr; \ + } \ + \ + ptr += size; \ + \ + if (card == CARD_r) { \ + if (validate_utf8 && \ + !_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_BadUtf8); \ + } \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + if (card != CARD_r && validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ + \ + longstr: \ + if (card == CARD_r) { \ + fastdecode_commitarr(dst + 1, &farr, sizeof(upb_StringView)); \ + } \ + ptr--; \ + if (validate_utf8) { \ + UPB_MUSTTAIL return fastdecode_longstring_utf8(d, ptr, msg, table, \ + hasbits, (uint64_t)dst); \ + } else { \ + UPB_MUSTTAIL return fastdecode_longstring_noutf8(d, ptr, msg, table, \ + hasbits, (uint64_t)dst); \ + } + +#define FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, card, \ + copyfunc, validate_utf8) \ + upb_StringView* dst; \ + fastdecode_arr farr; \ + int64_t size; \ + \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + RETURN_GENERIC("string field tag mismatch\n"); \ + } \ + \ + if (UPB_UNLIKELY((d->options & kUpb_DecodeOption_AliasString) == 0)) { \ + UPB_MUSTTAIL return copyfunc(UPB_PARSE_ARGS); \ + } \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_StringView), card); \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView)); \ + } \ + \ + size = (int8_t)ptr[tagbytes]; \ + ptr += tagbytes + 1; \ + dst->data = ptr; \ + dst->size = size; \ + \ + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->end))) { \ + ptr--; \ + if (validate_utf8) { \ + return fastdecode_longstring_utf8(d, ptr, msg, table, hasbits, \ + (uint64_t)dst); \ + } else { \ + return fastdecode_longstring_noutf8(d, ptr, msg, table, hasbits, \ + (uint64_t)dst); \ + } \ + } \ + \ + ptr += size; \ + \ + if (card == CARD_r) { \ + if (validate_utf8 && \ + !_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_BadUtf8); \ + } \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + if (UPB_UNLIKELY((d->options & kUpb_DecodeOption_AliasString) == 0)) { \ + /* Buffer flipped and we can't alias any more. Bounce to */ \ + /* copyfunc(), but via dispatch since we need to reload table */ \ + /* data also. */ \ + fastdecode_commitarr(dst, &farr, sizeof(upb_StringView)); \ + data = ret.tag; \ + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + } \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + if (card != CARD_r && validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +/* Generate all combinations: + * {p,c} x {s,o,r} x {s, b} x {1bt,2bt} */ + +#define s_VALIDATE true +#define b_VALIDATE false + +#define F(card, tagbytes, type) \ + UPB_NOINLINE \ + const char* upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + CARD_##card, type##_VALIDATE); \ + } \ + const char* upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + CARD_##card, upb_c##card##type##_##tagbytes##bt, \ + type##_VALIDATE); \ + } + +#define UTF8(card, tagbytes) \ + F(card, tagbytes, s) \ + F(card, tagbytes, b) + +#define TAGBYTES(card) \ + UTF8(card, 1) \ + UTF8(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) + +#undef s_VALIDATE +#undef b_VALIDATE +#undef F +#undef TAGBYTES +#undef FASTDECODE_LONGSTRING +#undef FASTDECODE_COPYSTRING +#undef FASTDECODE_STRING + +/* message fields *************************************************************/ + +UPB_INLINE +upb_Message* decode_newmsg_ceil(upb_Decoder* d, const upb_MiniTable* l, + int msg_ceil_bytes) { + size_t size = l->size + sizeof(upb_Message_Internal); + char* msg_data; + if (UPB_LIKELY(msg_ceil_bytes > 0 && + _upb_ArenaHas(&d->arena) >= msg_ceil_bytes)) { + UPB_ASSERT(size <= (size_t)msg_ceil_bytes); + msg_data = d->arena.head.ptr; + d->arena.head.ptr += size; + UPB_UNPOISON_MEMORY_REGION(msg_data, msg_ceil_bytes); + memset(msg_data, 0, msg_ceil_bytes); + UPB_POISON_MEMORY_REGION(msg_data + size, msg_ceil_bytes - size); + } else { + msg_data = (char*)upb_Arena_Malloc(&d->arena, size); + memset(msg_data, 0, size); + } + return msg_data + sizeof(upb_Message_Internal); +} + +typedef struct { + intptr_t table; + upb_Message* msg; +} fastdecode_submsgdata; + +UPB_FORCEINLINE +static const char* fastdecode_tosubmsg(upb_Decoder* d, const char* ptr, + void* ctx) { + fastdecode_submsgdata* submsg = ctx; + ptr = fastdecode_dispatch(d, ptr, submsg->msg, submsg->table, 0, 0); + UPB_ASSUME(ptr != NULL); + return ptr; +} + +#define FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, \ + msg_ceil_bytes, card) \ + \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + RETURN_GENERIC("submessage field tag mismatch\n"); \ + } \ + \ + if (--d->depth == 0) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_MaxDepthExceeded); \ + } \ + \ + upb_Message** dst; \ + uint32_t submsg_idx = (data >> 16) & 0xff; \ + const upb_MiniTable* tablep = decode_totablep(table); \ + const upb_MiniTable* subtablep = tablep->subs[submsg_idx].submsg; \ + fastdecode_submsgdata submsg = {decode_totable(subtablep)}; \ + fastdecode_arr farr; \ + \ + if (subtablep->table_mask == (uint8_t)-1) { \ + RETURN_GENERIC("submessage doesn't have fast tables."); \ + } \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_Message*), card); \ + \ + if (card == CARD_s) { \ + *(uint32_t*)msg |= hasbits; \ + hasbits = 0; \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_Message*)); \ + } \ + \ + submsg.msg = *dst; \ + \ + if (card == CARD_r || UPB_LIKELY(!submsg.msg)) { \ + *dst = submsg.msg = decode_newmsg_ceil(d, subtablep, msg_ceil_bytes); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_delimited(d, ptr, fastdecode_tosubmsg, &submsg); \ + \ + if (UPB_UNLIKELY(ptr == NULL || d->end_group != DECODE_NOGROUP)) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_Message*)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + d->depth++; \ + data = ret.tag; \ + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + d->depth++; \ + return ptr; \ + } \ + } \ + \ + d->depth++; \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +#define F(card, tagbytes, size_ceil, ceil_arg) \ + const char* upb_p##card##m_##tagbytes##bt_max##size_ceil##b( \ + UPB_PARSE_PARAMS) { \ + FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, ceil_arg, \ + CARD_##card); \ + } + +#define SIZES(card, tagbytes) \ + F(card, tagbytes, 64, 64) \ + F(card, tagbytes, 128, 128) \ + F(card, tagbytes, 192, 192) \ + F(card, tagbytes, 256, 256) \ + F(card, tagbytes, max, -1) + +#define TAGBYTES(card) \ + SIZES(card, 1) \ + SIZES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) + +#undef TAGBYTES +#undef SIZES +#undef F +#undef FASTDECODE_SUBMSG + +#endif /* UPB_FASTTABLE */ + + +#include +#include +#include +#include +#include +#include +#include + + +// Must be last. + +typedef struct { + const char *ptr, *end; + upb_Arena* arena; /* TODO: should we have a tmp arena for tmp data? */ + const upb_DefPool* symtab; + int depth; + upb_Status* status; + jmp_buf err; + int line; + const char* line_begin; + bool is_first; + int options; + const upb_FieldDef* debug_field; +} jsondec; + +enum { JD_OBJECT, JD_ARRAY, JD_STRING, JD_NUMBER, JD_TRUE, JD_FALSE, JD_NULL }; + +/* Forward declarations of mutually-recursive functions. */ +static void jsondec_wellknown(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); +static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f); +static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); +static void jsondec_object(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); + +static bool jsondec_streql(upb_StringView str, const char* lit) { + return str.size == strlen(lit) && memcmp(str.data, lit, str.size) == 0; +} + +static bool jsondec_isnullvalue(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Enum && + strcmp(upb_EnumDef_FullName(upb_FieldDef_EnumSubDef(f)), + "google.protobuf.NullValue") == 0; +} + +static bool jsondec_isvalue(const upb_FieldDef* f) { + return (upb_FieldDef_CType(f) == kUpb_CType_Message && + upb_MessageDef_WellKnownType(upb_FieldDef_MessageSubDef(f)) == + kUpb_WellKnown_Value) || + jsondec_isnullvalue(f); +} + +UPB_NORETURN static void jsondec_err(jsondec* d, const char* msg) { + upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: %s", d->line, + (int)(d->ptr - d->line_begin), msg); + UPB_LONGJMP(d->err, 1); +} + +UPB_PRINTF(2, 3) +UPB_NORETURN static void jsondec_errf(jsondec* d, const char* fmt, ...) { + va_list argp; + upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: ", d->line, + (int)(d->ptr - d->line_begin)); + va_start(argp, fmt); + upb_Status_VAppendErrorFormat(d->status, fmt, argp); + va_end(argp); + UPB_LONGJMP(d->err, 1); +} + +static void jsondec_skipws(jsondec* d) { + while (d->ptr != d->end) { + switch (*d->ptr) { + case '\n': + d->line++; + d->line_begin = d->ptr; + /* Fallthrough. */ + case '\r': + case '\t': + case ' ': + d->ptr++; + break; + default: + return; + } + } + jsondec_err(d, "Unexpected EOF"); +} + +static bool jsondec_tryparsech(jsondec* d, char ch) { + if (d->ptr == d->end || *d->ptr != ch) return false; + d->ptr++; + return true; +} + +static void jsondec_parselit(jsondec* d, const char* lit) { + size_t avail = d->end - d->ptr; + size_t len = strlen(lit); + if (avail < len || memcmp(d->ptr, lit, len) != 0) { + jsondec_errf(d, "Expected: '%s'", lit); + } + d->ptr += len; +} + +static void jsondec_wsch(jsondec* d, char ch) { + jsondec_skipws(d); + if (!jsondec_tryparsech(d, ch)) { + jsondec_errf(d, "Expected: '%c'", ch); + } +} + +static void jsondec_true(jsondec* d) { jsondec_parselit(d, "true"); } +static void jsondec_false(jsondec* d) { jsondec_parselit(d, "false"); } +static void jsondec_null(jsondec* d) { jsondec_parselit(d, "null"); } + +static void jsondec_entrysep(jsondec* d) { + jsondec_skipws(d); + jsondec_parselit(d, ":"); +} + +static int jsondec_rawpeek(jsondec* d) { + switch (*d->ptr) { + case '{': + return JD_OBJECT; + case '[': + return JD_ARRAY; + case '"': + return JD_STRING; + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return JD_NUMBER; + case 't': + return JD_TRUE; + case 'f': + return JD_FALSE; + case 'n': + return JD_NULL; + default: + jsondec_errf(d, "Unexpected character: '%c'", *d->ptr); + } +} + +/* JSON object/array **********************************************************/ + +/* These are used like so: + * + * jsondec_objstart(d); + * while (jsondec_objnext(d)) { + * ... + * } + * jsondec_objend(d) */ + +static int jsondec_peek(jsondec* d) { + jsondec_skipws(d); + return jsondec_rawpeek(d); +} + +static void jsondec_push(jsondec* d) { + if (--d->depth < 0) { + jsondec_err(d, "Recursion limit exceeded"); + } + d->is_first = true; +} + +static bool jsondec_seqnext(jsondec* d, char end_ch) { + bool is_first = d->is_first; + d->is_first = false; + jsondec_skipws(d); + if (*d->ptr == end_ch) return false; + if (!is_first) jsondec_parselit(d, ","); + return true; +} + +static void jsondec_arrstart(jsondec* d) { + jsondec_push(d); + jsondec_wsch(d, '['); +} + +static void jsondec_arrend(jsondec* d) { + d->depth++; + jsondec_wsch(d, ']'); +} + +static bool jsondec_arrnext(jsondec* d) { return jsondec_seqnext(d, ']'); } + +static void jsondec_objstart(jsondec* d) { + jsondec_push(d); + jsondec_wsch(d, '{'); +} + +static void jsondec_objend(jsondec* d) { + d->depth++; + jsondec_wsch(d, '}'); +} + +static bool jsondec_objnext(jsondec* d) { + if (!jsondec_seqnext(d, '}')) return false; + if (jsondec_peek(d) != JD_STRING) { + jsondec_err(d, "Object must start with string"); + } + return true; +} + +/* JSON number ****************************************************************/ + +static bool jsondec_tryskipdigits(jsondec* d) { + const char* start = d->ptr; + + while (d->ptr < d->end) { + if (*d->ptr < '0' || *d->ptr > '9') { break; } - case kUpb_FieldType_Message: { - size_t size; - void* submsg = *(void**)field_mem; - const upb_MiniTable* subm = subs[f->submsg_index].submsg; - if (submsg == NULL) { - return; - } - if (--e->depth == 0) encode_err(e); - encode_message(e, submsg, subm, &size); - encode_varint(e, size); - wire_type = kUpb_WireType_Delimited; - e->depth++; - break; + d->ptr++; + } + + return d->ptr != start; +} + +static void jsondec_skipdigits(jsondec* d) { + if (!jsondec_tryskipdigits(d)) { + jsondec_err(d, "Expected one or more digits"); + } +} + +static double jsondec_number(jsondec* d) { + const char* start = d->ptr; + + assert(jsondec_rawpeek(d) == JD_NUMBER); + + /* Skip over the syntax of a number, as specified by JSON. */ + if (*d->ptr == '-') d->ptr++; + + if (jsondec_tryparsech(d, '0')) { + if (jsondec_tryskipdigits(d)) { + jsondec_err(d, "number cannot have leading zero"); + } + } else { + jsondec_skipdigits(d); + } + + if (d->ptr == d->end) goto parse; + if (jsondec_tryparsech(d, '.')) { + jsondec_skipdigits(d); + } + if (d->ptr == d->end) goto parse; + + if (*d->ptr == 'e' || *d->ptr == 'E') { + d->ptr++; + if (d->ptr == d->end) { + jsondec_err(d, "Unexpected EOF in number"); + } + if (*d->ptr == '+' || *d->ptr == '-') { + d->ptr++; } - default: - UPB_UNREACHABLE(); + jsondec_skipdigits(d); } -#undef CASE - encode_tag(e, f->number, wire_type); +parse: + /* Having verified the syntax of a JSON number, use strtod() to parse + * (strtod() accepts a superset of JSON syntax). */ + errno = 0; + { + char* end; + double val = strtod(start, &end); + assert(end == d->ptr); + + /* Currently the min/max-val conformance tests fail if we check this. Does + * this mean the conformance tests are wrong or strtod() is wrong, or + * something else? Investigate further. */ + /* + if (errno == ERANGE) { + jsondec_err(d, "Number out of range"); + } + */ + + if (val > DBL_MAX || val < -DBL_MAX) { + jsondec_err(d, "Number out of range"); + } + + return val; + } } -static void encode_array(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { - const upb_Array* arr = *UPB_PTR_AT(msg, f->offset, upb_Array*); - bool packed = f->mode & upb_LabelFlags_IsPacked; - size_t pre_len = e->limit - e->ptr; +/* JSON string ****************************************************************/ - if (arr == NULL || arr->len == 0) { - return; +static char jsondec_escape(jsondec* d) { + switch (*d->ptr++) { + case '"': + return '\"'; + case '\\': + return '\\'; + case '/': + return '/'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + default: + jsondec_err(d, "Invalid escape char"); } +} -#define VARINT_CASE(ctype, encode) \ - { \ - const ctype* start = _upb_array_constptr(arr); \ - const ctype* ptr = start + arr->len; \ - uint32_t tag = packed ? 0 : (f->number << 3) | kUpb_WireType_Varint; \ - do { \ - ptr--; \ - encode_varint(e, encode); \ - if (tag) encode_varint(e, tag); \ - } while (ptr != start); \ - } \ - break; +static uint32_t jsondec_codepoint(jsondec* d) { + uint32_t cp = 0; + const char* end; -#define TAG(wire_type) (packed ? 0 : (f->number << 3 | wire_type)) + if (d->end - d->ptr < 4) { + jsondec_err(d, "EOF inside string"); + } - switch (f->descriptortype) { - case kUpb_FieldType_Double: - encode_fixedarray(e, arr, sizeof(double), TAG(kUpb_WireType_64Bit)); - break; - case kUpb_FieldType_Float: - encode_fixedarray(e, arr, sizeof(float), TAG(kUpb_WireType_32Bit)); - break; - case kUpb_FieldType_SFixed64: - case kUpb_FieldType_Fixed64: - encode_fixedarray(e, arr, sizeof(uint64_t), TAG(kUpb_WireType_64Bit)); - break; - case kUpb_FieldType_Fixed32: - case kUpb_FieldType_SFixed32: - encode_fixedarray(e, arr, sizeof(uint32_t), TAG(kUpb_WireType_32Bit)); - break; - case kUpb_FieldType_Int64: - case kUpb_FieldType_UInt64: - VARINT_CASE(uint64_t, *ptr); - case kUpb_FieldType_UInt32: - VARINT_CASE(uint32_t, *ptr); - case kUpb_FieldType_Int32: - case kUpb_FieldType_Enum: - VARINT_CASE(int32_t, (int64_t)*ptr); - case kUpb_FieldType_Bool: - VARINT_CASE(bool, *ptr); - case kUpb_FieldType_SInt32: - VARINT_CASE(int32_t, encode_zz32(*ptr)); - case kUpb_FieldType_SInt64: - VARINT_CASE(int64_t, encode_zz64(*ptr)); - case kUpb_FieldType_String: - case kUpb_FieldType_Bytes: { - const upb_StringView* start = _upb_array_constptr(arr); - const upb_StringView* ptr = start + arr->len; - do { - ptr--; - encode_bytes(e, ptr->data, ptr->size); - encode_varint(e, ptr->size); - encode_tag(e, f->number, kUpb_WireType_Delimited); - } while (ptr != start); - return; - } - case kUpb_FieldType_Group: { - const void* const* start = _upb_array_constptr(arr); - const void* const* ptr = start + arr->len; - const upb_MiniTable* subm = subs[f->submsg_index].submsg; - if (--e->depth == 0) encode_err(e); - do { - size_t size; - ptr--; - encode_tag(e, f->number, kUpb_WireType_EndGroup); - encode_message(e, *ptr, subm, &size); - encode_tag(e, f->number, kUpb_WireType_StartGroup); - } while (ptr != start); - e->depth++; - return; - } - case kUpb_FieldType_Message: { - const void* const* start = _upb_array_constptr(arr); - const void* const* ptr = start + arr->len; - const upb_MiniTable* subm = subs[f->submsg_index].submsg; - if (--e->depth == 0) encode_err(e); - do { - size_t size; - ptr--; - encode_message(e, *ptr, subm, &size); - encode_varint(e, size); - encode_tag(e, f->number, kUpb_WireType_Delimited); - } while (ptr != start); - e->depth++; - return; + end = d->ptr + 4; + while (d->ptr < end) { + char ch = *d->ptr++; + if (ch >= '0' && ch <= '9') { + ch -= '0'; + } else if (ch >= 'a' && ch <= 'f') { + ch = ch - 'a' + 10; + } else if (ch >= 'A' && ch <= 'F') { + ch = ch - 'A' + 10; + } else { + jsondec_err(d, "Invalid hex digit"); } + cp = (cp << 4) | ch; } -#undef VARINT_CASE - if (packed) { - encode_varint(e, e->limit - e->ptr - pre_len); - encode_tag(e, f->number, kUpb_WireType_Delimited); + return cp; +} + +/* Parses a \uXXXX unicode escape (possibly a surrogate pair). */ +static size_t jsondec_unicode(jsondec* d, char* out) { + uint32_t cp = jsondec_codepoint(d); + if (upb_Unicode_IsHigh(cp)) { + /* Surrogate pair: two 16-bit codepoints become a 32-bit codepoint. */ + jsondec_parselit(d, "\\u"); + uint32_t low = jsondec_codepoint(d); + if (!upb_Unicode_IsLow(low)) jsondec_err(d, "Invalid low surrogate"); + cp = upb_Unicode_FromPair(cp, low); + } else if (upb_Unicode_IsLow(cp)) { + jsondec_err(d, "Unpaired low surrogate"); } + + /* Write to UTF-8 */ + int bytes = upb_Unicode_ToUTF8(cp, out); + if (bytes == 0) jsondec_err(d, "Invalid codepoint"); + return bytes; } -static void encode_mapentry(upb_encstate* e, uint32_t number, - const upb_MiniTable* layout, - const upb_MapEntry* ent) { - const upb_MiniTable_Field* key_field = &layout->fields[0]; - const upb_MiniTable_Field* val_field = &layout->fields[1]; - size_t pre_len = e->limit - e->ptr; - size_t size; - encode_scalar(e, &ent->v, layout->subs, val_field); - encode_scalar(e, &ent->k, layout->subs, key_field); - size = (e->limit - e->ptr) - pre_len; - encode_varint(e, size); - encode_tag(e, number, kUpb_WireType_Delimited); +static void jsondec_resize(jsondec* d, char** buf, char** end, char** buf_end) { + size_t oldsize = *buf_end - *buf; + size_t len = *end - *buf; + size_t size = UPB_MAX(8, 2 * oldsize); + + *buf = upb_Arena_Realloc(d->arena, *buf, len, size); + if (!*buf) jsondec_err(d, "Out of memory"); + + *end = *buf + len; + *buf_end = *buf + size; } -static void encode_map(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { - const upb_Map* map = *UPB_PTR_AT(msg, f->offset, const upb_Map*); - const upb_MiniTable* layout = subs[f->submsg_index].submsg; - UPB_ASSERT(layout->field_count == 2); +static upb_StringView jsondec_string(jsondec* d) { + char* buf = NULL; + char* end = NULL; + char* buf_end = NULL; - if (map == NULL) return; + jsondec_skipws(d); - if (e->options & kUpb_Encode_Deterministic) { - _upb_sortedmap sorted; - _upb_mapsorter_pushmap(&e->sorter, layout->fields[0].descriptortype, map, - &sorted); - upb_MapEntry ent; - while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) { - encode_mapentry(e, f->number, layout, &ent); - } - _upb_mapsorter_popmap(&e->sorter, &sorted); - } else { - upb_strtable_iter i; - upb_strtable_begin(&i, &map->table); - for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { - upb_StringView key = upb_strtable_iter_key(&i); - const upb_value val = upb_strtable_iter_value(&i); - upb_MapEntry ent; - _upb_map_fromkey(key, &ent.k, map->key_size); - _upb_map_fromvalue(val, &ent.v, map->val_size); - encode_mapentry(e, f->number, layout, &ent); - } + if (*d->ptr++ != '"') { + jsondec_err(d, "Expected string"); } -} -static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { - if (f->presence == 0) { - /* Proto3 presence or map/array. */ - const void* mem = UPB_PTR_AT(msg, f->offset, void); - switch (f->mode >> upb_FieldRep_Shift) { - case upb_FieldRep_1Byte: { - char ch; - memcpy(&ch, mem, 1); - return ch != 0; - } - case upb_FieldRep_4Byte: { - uint32_t u32; - memcpy(&u32, mem, 4); - return u32 != 0; - } - case upb_FieldRep_8Byte: { - uint64_t u64; - memcpy(&u64, mem, 8); - return u64 != 0; - } - case upb_FieldRep_StringView: { - const upb_StringView* str = (const upb_StringView*)mem; - return str->size != 0; + while (d->ptr < d->end) { + char ch = *d->ptr++; + + if (end == buf_end) { + jsondec_resize(d, &buf, &end, &buf_end); + } + + switch (ch) { + case '"': { + upb_StringView ret; + ret.data = buf; + ret.size = end - buf; + *end = '\0'; /* Needed for possible strtod(). */ + return ret; } + case '\\': + if (d->ptr == d->end) goto eof; + if (*d->ptr == 'u') { + d->ptr++; + if (buf_end - end < 4) { + /* Allow space for maximum-sized codepoint (4 bytes). */ + jsondec_resize(d, &buf, &end, &buf_end); + } + end += jsondec_unicode(d, end); + } else { + *end++ = jsondec_escape(d); + } + break; default: - UPB_UNREACHABLE(); + if ((unsigned char)*d->ptr < 0x20) { + jsondec_err(d, "Invalid char in JSON string"); + } + *end++ = ch; + break; } - } else if (f->presence > 0) { - /* Proto2 presence: hasbit. */ - return _upb_hasbit_field(msg, f); - } else { - /* Field is in a oneof. */ - return _upb_getoneofcase_field(msg, f) == f->number; } + +eof: + jsondec_err(d, "EOF inside string"); } -static void encode_field(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field) { - switch (upb_FieldMode_Get(field)) { - case kUpb_FieldMode_Array: - encode_array(e, msg, subs, field); +static void jsondec_skipval(jsondec* d) { + switch (jsondec_peek(d)) { + case JD_OBJECT: + jsondec_objstart(d); + while (jsondec_objnext(d)) { + jsondec_string(d); + jsondec_entrysep(d); + jsondec_skipval(d); + } + jsondec_objend(d); break; - case kUpb_FieldMode_Map: - encode_map(e, msg, subs, field); + case JD_ARRAY: + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + jsondec_skipval(d); + } + jsondec_arrend(d); break; - case kUpb_FieldMode_Scalar: - encode_scalar(e, UPB_PTR_AT(msg, field->offset, void), subs, field); + case JD_TRUE: + jsondec_true(d); + break; + case JD_FALSE: + jsondec_false(d); + break; + case JD_NULL: + jsondec_null(d); + break; + case JD_STRING: + jsondec_string(d); + break; + case JD_NUMBER: + jsondec_number(d); break; - default: - UPB_UNREACHABLE(); } } -/* message MessageSet { - * repeated group Item = 1 { - * required int32 type_id = 2; - * required string message = 3; - * } - * } */ -static void encode_msgset_item(upb_encstate* e, - const upb_Message_Extension* ext) { - size_t size; - encode_tag(e, 1, kUpb_WireType_EndGroup); - encode_message(e, ext->data.ptr, ext->ext->sub.submsg, &size); - encode_varint(e, size); - encode_tag(e, 3, kUpb_WireType_Delimited); - encode_varint(e, ext->ext->field.number); - encode_tag(e, 2, kUpb_WireType_Varint); - encode_tag(e, 1, kUpb_WireType_StartGroup); -} - -static void encode_message(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable* m, size_t* size) { - size_t pre_len = e->limit - e->ptr; +/* Base64 decoding for bytes fields. ******************************************/ - if ((e->options & kUpb_Encode_CheckRequired) && m->required_count) { - uint64_t msg_head; - memcpy(&msg_head, msg, 8); - msg_head = _upb_BigEndian_Swap64(msg_head); - if (upb_MiniTable_requiredmask(m) & ~msg_head) { - encode_err(e); - } - } +static unsigned int jsondec_base64_tablelookup(const char ch) { + /* Table includes the normal base64 chars plus the URL-safe variant. */ + const signed char table[256] = { + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, 62 /*+*/, -1, 62 /*-*/, -1, 63 /*/ */, 52 /*0*/, + 53 /*1*/, 54 /*2*/, 55 /*3*/, 56 /*4*/, 57 /*5*/, 58 /*6*/, 59 /*7*/, + 60 /*8*/, 61 /*9*/, -1, -1, -1, -1, -1, + -1, -1, 0 /*A*/, 1 /*B*/, 2 /*C*/, 3 /*D*/, 4 /*E*/, + 5 /*F*/, 6 /*G*/, 07 /*H*/, 8 /*I*/, 9 /*J*/, 10 /*K*/, 11 /*L*/, + 12 /*M*/, 13 /*N*/, 14 /*O*/, 15 /*P*/, 16 /*Q*/, 17 /*R*/, 18 /*S*/, + 19 /*T*/, 20 /*U*/, 21 /*V*/, 22 /*W*/, 23 /*X*/, 24 /*Y*/, 25 /*Z*/, + -1, -1, -1, -1, 63 /*_*/, -1, 26 /*a*/, + 27 /*b*/, 28 /*c*/, 29 /*d*/, 30 /*e*/, 31 /*f*/, 32 /*g*/, 33 /*h*/, + 34 /*i*/, 35 /*j*/, 36 /*k*/, 37 /*l*/, 38 /*m*/, 39 /*n*/, 40 /*o*/, + 41 /*p*/, 42 /*q*/, 43 /*r*/, 44 /*s*/, 45 /*t*/, 46 /*u*/, 47 /*v*/, + 48 /*w*/, 49 /*x*/, 50 /*y*/, 51 /*z*/, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1}; - if ((e->options & kUpb_Encode_SkipUnknown) == 0) { - size_t unknown_size; - const char* unknown = upb_Message_GetUnknown(msg, &unknown_size); + /* Sign-extend return value so high bit will be set on any unexpected char. */ + return table[(unsigned)ch]; +} - if (unknown) { - encode_bytes(e, unknown, unknown_size); - } - } +static char* jsondec_partialbase64(jsondec* d, const char* ptr, const char* end, + char* out) { + int32_t val = -1; - if (m->ext != upb_ExtMode_NonExtendable) { - /* Encode all extensions together. Unlike C++, we do not attempt to keep - * these in field number order relative to normal fields or even to each - * other. */ - size_t ext_count; - const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &ext_count); - if (ext_count) { - const upb_Message_Extension* end = ext + ext_count; - for (; ext != end; ext++) { - if (UPB_UNLIKELY(m->ext == upb_ExtMode_IsMessageSet)) { - encode_msgset_item(e, ext); - } else { - encode_field(e, &ext->data, &ext->ext->sub, &ext->ext->field); - } - } - } + switch (end - ptr) { + case 2: + val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12; + out[0] = val >> 16; + out += 1; + break; + case 3: + val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12 | + jsondec_base64_tablelookup(ptr[2]) << 6; + out[0] = val >> 16; + out[1] = (val >> 8) & 0xff; + out += 2; + break; } - if (m->field_count) { - const upb_MiniTable_Field* f = &m->fields[m->field_count]; - const upb_MiniTable_Field* first = &m->fields[0]; - while (f != first) { - f--; - if (encode_shouldencode(e, msg, m->subs, f)) { - encode_field(e, msg, m->subs, f); - } - } + if (val < 0) { + jsondec_err(d, "Corrupt base64"); } - *size = (e->limit - e->ptr) - pre_len; + return out; } -char* upb_Encode(const void* msg, const upb_MiniTable* l, int options, - upb_Arena* arena, size_t* size) { - upb_encstate e; - unsigned depth = (unsigned)options >> 16; +static size_t jsondec_base64(jsondec* d, upb_StringView str) { + /* We decode in place. This is safe because this is a new buffer (not + * aliasing the input) and because base64 decoding shrinks 4 bytes into 3. */ + char* out = (char*)str.data; + const char* ptr = str.data; + const char* end = ptr + str.size; + const char* end4 = ptr + (str.size & -4); /* Round down to multiple of 4. */ - e.alloc = upb_Arena_Alloc(arena); - e.buf = NULL; - e.limit = NULL; - e.ptr = NULL; - e.depth = depth ? depth : 64; - e.options = options; - _upb_mapsorter_init(&e.sorter); - char* ret = NULL; + for (; ptr < end4; ptr += 4, out += 3) { + int val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12 | + jsondec_base64_tablelookup(ptr[2]) << 6 | + jsondec_base64_tablelookup(ptr[3]) << 0; - if (UPB_SETJMP(e.err)) { - *size = 0; - ret = NULL; - } else { - encode_message(&e, msg, l, size); - *size = e.limit - e.ptr; - if (*size == 0) { - static char ch; - ret = &ch; - } else { - UPB_ASSERT(e.ptr); - ret = e.ptr; + if (val < 0) { + /* Junk chars or padding. Remove trailing padding, if any. */ + if (end - ptr == 4 && ptr[3] == '=') { + if (ptr[2] == '=') { + end -= 2; + } else { + end -= 1; + } + } + break; } - } - - _upb_mapsorter_destroy(&e.sorter); - return ret; -} - -/** upb/msg.c ************************************************************/ - -/** upb_Message - * *******************************************************************/ - -static const size_t overhead = sizeof(upb_Message_InternalData); + out[0] = val >> 16; + out[1] = (val >> 8) & 0xff; + out[2] = val & 0xff; + } -static const upb_Message_Internal* upb_Message_Getinternal_const( - const upb_Message* msg) { - ptrdiff_t size = sizeof(upb_Message_Internal); - return (upb_Message_Internal*)((char*)msg - size); -} + if (ptr < end) { + /* Process remaining chars. We do not require padding. */ + out = jsondec_partialbase64(d, ptr, end, out); + } -upb_Message* _upb_Message_New(const upb_MiniTable* l, upb_Arena* a) { - return _upb_Message_New_inl(l, a); + return out - str.data; } -void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l) { - void* mem = UPB_PTR_AT(msg, -sizeof(upb_Message_Internal), char); - memset(mem, 0, upb_msg_sizeof(l)); -} +/* Low-level integer parsing **************************************************/ -static bool realloc_internal(upb_Message* msg, size_t need, upb_Arena* arena) { - upb_Message_Internal* in = upb_Message_Getinternal(msg); - if (!in->internal) { - /* No internal data, allocate from scratch. */ - size_t size = UPB_MAX(128, _upb_Log2Ceilingsize(need + overhead)); - upb_Message_InternalData* internal = upb_Arena_Malloc(arena, size); - if (!internal) return false; - internal->size = size; - internal->unknown_end = overhead; - internal->ext_begin = size; - in->internal = internal; - } else if (in->internal->ext_begin - in->internal->unknown_end < need) { - /* Internal data is too small, reallocate. */ - size_t new_size = _upb_Log2Ceilingsize(in->internal->size + need); - size_t ext_bytes = in->internal->size - in->internal->ext_begin; - size_t new_ext_begin = new_size - ext_bytes; - upb_Message_InternalData* internal = - upb_Arena_Realloc(arena, in->internal, in->internal->size, new_size); - if (!internal) return false; - if (ext_bytes) { - /* Need to move extension data to the end. */ - char* ptr = (char*)internal; - memmove(ptr + new_ext_begin, ptr + internal->ext_begin, ext_bytes); - } - internal->ext_begin = new_ext_begin; - internal->size = new_size; - in->internal = internal; - } - UPB_ASSERT(in->internal->ext_begin - in->internal->unknown_end >= need); - return true; +static const char* jsondec_buftouint64(jsondec* d, const char* ptr, + const char* end, uint64_t* val) { + const char* out = upb_BufToUint64(ptr, end, val); + if (!out) jsondec_err(d, "Integer overflow"); + return out; } -bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, - upb_Arena* arena) { - if (!realloc_internal(msg, len, arena)) return false; - upb_Message_Internal* in = upb_Message_Getinternal(msg); - memcpy(UPB_PTR_AT(in->internal, in->internal->unknown_end, char), data, len); - in->internal->unknown_end += len; - return true; +static const char* jsondec_buftoint64(jsondec* d, const char* ptr, + const char* end, int64_t* val, + bool* is_neg) { + const char* out = upb_BufToInt64(ptr, end, val, is_neg); + if (!out) jsondec_err(d, "Integer overflow"); + return out; } -void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) { - upb_Message_Internal* in = upb_Message_Getinternal(msg); - if (in->internal) { - in->internal->unknown_end = overhead; +static uint64_t jsondec_strtouint64(jsondec* d, upb_StringView str) { + const char* end = str.data + str.size; + uint64_t ret; + if (jsondec_buftouint64(d, str.data, end, &ret) != end) { + jsondec_err(d, "Non-number characters in quoted integer"); } + return ret; } -const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len) { - const upb_Message_Internal* in = upb_Message_Getinternal_const(msg); - if (in->internal) { - *len = in->internal->unknown_end - overhead; - return (char*)(in->internal + 1); - } else { - *len = 0; - return NULL; +static int64_t jsondec_strtoint64(jsondec* d, upb_StringView str) { + const char* end = str.data + str.size; + int64_t ret; + if (jsondec_buftoint64(d, str.data, end, &ret, NULL) != end) { + jsondec_err(d, "Non-number characters in quoted integer"); } + return ret; } -const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg, - size_t* count) { - const upb_Message_Internal* in = upb_Message_Getinternal_const(msg); - if (in->internal) { - *count = (in->internal->size - in->internal->ext_begin) / - sizeof(upb_Message_Extension); - return UPB_PTR_AT(in->internal, in->internal->ext_begin, void); - } else { - *count = 0; - return NULL; - } -} +/* Primitive value types ******************************************************/ -const upb_Message_Extension* _upb_Message_Getext( - const upb_Message* msg, const upb_MiniTable_Extension* e) { - size_t n; - const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &n); +/* Parse INT32 or INT64 value. */ +static upb_MessageValue jsondec_int(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val; - /* For now we use linear search exclusively to find extensions. If this - * becomes an issue due to messages with lots of extensions, we can introduce - * a table of some sort. */ - for (size_t i = 0; i < n; i++) { - if (ext[i].ext == e) { - return &ext[i]; + switch (jsondec_peek(d)) { + case JD_NUMBER: { + double dbl = jsondec_number(d); + if (dbl > 9223372036854774784.0 || dbl < -9223372036854775808.0) { + jsondec_err(d, "JSON number is out of range."); + } + val.int64_val = dbl; /* must be guarded, overflow here is UB */ + if (val.int64_val != dbl) { + jsondec_errf(d, "JSON number was not integral (%f != %" PRId64 ")", dbl, + val.int64_val); + } + break; + } + case JD_STRING: { + upb_StringView str = jsondec_string(d); + val.int64_val = jsondec_strtoint64(d, str); + break; } + default: + jsondec_err(d, "Expected number or string"); } - return NULL; -} - -void _upb_Message_Clearext(upb_Message* msg, - const upb_MiniTable_Extension* ext_l) { - upb_Message_Internal* in = upb_Message_Getinternal(msg); - if (!in->internal) return; - const upb_Message_Extension* base = - UPB_PTR_AT(in->internal, in->internal->ext_begin, void); - upb_Message_Extension* ext = - (upb_Message_Extension*)_upb_Message_Getext(msg, ext_l); - if (ext) { - *ext = *base; - in->internal->ext_begin += sizeof(upb_Message_Extension); + if (upb_FieldDef_CType(f) == kUpb_CType_Int32 || + upb_FieldDef_CType(f) == kUpb_CType_Enum) { + if (val.int64_val > INT32_MAX || val.int64_val < INT32_MIN) { + jsondec_err(d, "Integer out of range."); + } + val.int32_val = (int32_t)val.int64_val; } -} -upb_Message_Extension* _upb_Message_Getorcreateext( - upb_Message* msg, const upb_MiniTable_Extension* e, upb_Arena* arena) { - upb_Message_Extension* ext = - (upb_Message_Extension*)_upb_Message_Getext(msg, e); - if (ext) return ext; - if (!realloc_internal(msg, sizeof(upb_Message_Extension), arena)) return NULL; - upb_Message_Internal* in = upb_Message_Getinternal(msg); - in->internal->ext_begin -= sizeof(upb_Message_Extension); - ext = UPB_PTR_AT(in->internal, in->internal->ext_begin, void); - memset(ext, 0, sizeof(upb_Message_Extension)); - ext->ext = e; - return ext; -} - -size_t upb_Message_ExtensionCount(const upb_Message* msg) { - size_t count; - _upb_Message_Getexts(msg, &count); - return count; + return val; } -/** upb_Array *****************************************************************/ - -bool _upb_array_realloc(upb_Array* arr, size_t min_size, upb_Arena* arena) { - size_t new_size = UPB_MAX(arr->size, 4); - int elem_size_lg2 = arr->data & 7; - size_t old_bytes = arr->size << elem_size_lg2; - size_t new_bytes; - void* ptr = _upb_array_ptr(arr); - - /* Log2 ceiling of size. */ - while (new_size < min_size) new_size *= 2; +/* Parse UINT32 or UINT64 value. */ +static upb_MessageValue jsondec_uint(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val = {0}; - new_bytes = new_size << elem_size_lg2; - ptr = upb_Arena_Realloc(arena, ptr, old_bytes, new_bytes); + switch (jsondec_peek(d)) { + case JD_NUMBER: { + double dbl = jsondec_number(d); + if (dbl > 18446744073709549568.0 || dbl < 0) { + jsondec_err(d, "JSON number is out of range."); + } + val.uint64_val = dbl; /* must be guarded, overflow here is UB */ + if (val.uint64_val != dbl) { + jsondec_errf(d, "JSON number was not integral (%f != %" PRIu64 ")", dbl, + val.uint64_val); + } + break; + } + case JD_STRING: { + upb_StringView str = jsondec_string(d); + val.uint64_val = jsondec_strtouint64(d, str); + break; + } + default: + jsondec_err(d, "Expected number or string"); + } - if (!ptr) { - return false; + if (upb_FieldDef_CType(f) == kUpb_CType_UInt32) { + if (val.uint64_val > UINT32_MAX) { + jsondec_err(d, "Integer out of range."); + } + val.uint32_val = (uint32_t)val.uint64_val; } - arr->data = _upb_tag_arrptr(ptr, elem_size_lg2); - arr->size = new_size; - return true; + return val; } -static upb_Array* getorcreate_array(upb_Array** arr_ptr, int elem_size_lg2, - upb_Arena* arena) { - upb_Array* arr = *arr_ptr; - if (!arr) { - arr = _upb_Array_New(arena, 4, elem_size_lg2); - if (!arr) return NULL; - *arr_ptr = arr; - } - return arr; -} +/* Parse DOUBLE or FLOAT value. */ +static upb_MessageValue jsondec_double(jsondec* d, const upb_FieldDef* f) { + upb_StringView str; + upb_MessageValue val = {0}; -void* _upb_Array_Resize_fallback(upb_Array** arr_ptr, size_t size, - int elem_size_lg2, upb_Arena* arena) { - upb_Array* arr = getorcreate_array(arr_ptr, elem_size_lg2, arena); - return arr && _upb_Array_Resize(arr, size, arena) ? _upb_array_ptr(arr) - : NULL; -} + switch (jsondec_peek(d)) { + case JD_NUMBER: + val.double_val = jsondec_number(d); + break; + case JD_STRING: + str = jsondec_string(d); + if (jsondec_streql(str, "NaN")) { + val.double_val = NAN; + } else if (jsondec_streql(str, "Infinity")) { + val.double_val = INFINITY; + } else if (jsondec_streql(str, "-Infinity")) { + val.double_val = -INFINITY; + } else { + val.double_val = strtod(str.data, NULL); + } + break; + default: + jsondec_err(d, "Expected number or string"); + } -bool _upb_Array_Append_fallback(upb_Array** arr_ptr, const void* value, - int elem_size_lg2, upb_Arena* arena) { - upb_Array* arr = getorcreate_array(arr_ptr, elem_size_lg2, arena); - if (!arr) return false; + if (upb_FieldDef_CType(f) == kUpb_CType_Float) { + float f = val.double_val; + if (val.double_val != INFINITY && val.double_val != -INFINITY) { + if (f == INFINITY || f == -INFINITY) jsondec_err(d, "Float out of range"); + } + val.float_val = f; + } - size_t elems = arr->len; + return val; +} - if (!_upb_Array_Resize(arr, elems + 1, arena)) { - return false; +/* Parse STRING or BYTES value. */ +static upb_MessageValue jsondec_strfield(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val; + val.str_val = jsondec_string(d); + if (upb_FieldDef_CType(f) == kUpb_CType_Bytes) { + val.str_val.size = jsondec_base64(d, val.str_val); } - - char* data = _upb_array_ptr(arr); - memcpy(data + (elems << elem_size_lg2), value, 1 << elem_size_lg2); - return true; + return val; } -/** upb_Map *******************************************************************/ +static upb_MessageValue jsondec_enum(jsondec* d, const upb_FieldDef* f) { + switch (jsondec_peek(d)) { + case JD_STRING: { + upb_StringView str = jsondec_string(d); + const upb_EnumDef* e = upb_FieldDef_EnumSubDef(f); + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByNameWithSize(e, str.data, str.size); + upb_MessageValue val; + if (ev) { + val.int32_val = upb_EnumValueDef_Number(ev); + } else { + if (d->options & upb_JsonDecode_IgnoreUnknown) { + val.int32_val = 0; + } else { + jsondec_errf(d, "Unknown enumerator: '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(str)); + } + } + return val; + } + case JD_NULL: { + if (jsondec_isnullvalue(f)) { + upb_MessageValue val; + jsondec_null(d); + val.int32_val = 0; + return val; + } + } + /* Fallthrough. */ + default: + return jsondec_int(d, f); + } +} -upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size) { - upb_Map* map = upb_Arena_Malloc(a, sizeof(upb_Map)); +static upb_MessageValue jsondec_bool(jsondec* d, const upb_FieldDef* f) { + bool is_map_key = upb_FieldDef_Number(f) == 1 && + upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f)); + upb_MessageValue val; - if (!map) { - return NULL; + if (is_map_key) { + upb_StringView str = jsondec_string(d); + if (jsondec_streql(str, "true")) { + val.bool_val = true; + } else if (jsondec_streql(str, "false")) { + val.bool_val = false; + } else { + jsondec_err(d, "Invalid boolean map key"); + } + } else { + switch (jsondec_peek(d)) { + case JD_TRUE: + val.bool_val = true; + jsondec_true(d); + break; + case JD_FALSE: + val.bool_val = false; + jsondec_false(d); + break; + default: + jsondec_err(d, "Expected true or false"); + } } - upb_strtable_init(&map->table, 4, a); - map->key_size = key_size; - map->val_size = value_size; - - return map; + return val; } -static void _upb_mapsorter_getkeys(const void* _a, const void* _b, void* a_key, - void* b_key, size_t size) { - const upb_tabent* const* a = _a; - const upb_tabent* const* b = _b; - upb_StringView a_tabkey = upb_tabstrview((*a)->key); - upb_StringView b_tabkey = upb_tabstrview((*b)->key); - _upb_map_fromkey(a_tabkey, a_key, size); - _upb_map_fromkey(b_tabkey, b_key, size); -} +/* Composite types (array/message/map) ****************************************/ -#define UPB_COMPARE_INTEGERS(a, b) ((a) < (b) ? -1 : ((a) == (b) ? 0 : 1)) +static void jsondec_array(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { + upb_Array* arr = upb_Message_Mutable(msg, f, d->arena).array; -static int _upb_mapsorter_cmpi64(const void* _a, const void* _b) { - int64_t a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); - return UPB_COMPARE_INTEGERS(a, b); + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + upb_MessageValue elem = jsondec_value(d, f); + upb_Array_Append(arr, elem, d->arena); + } + jsondec_arrend(d); } -static int _upb_mapsorter_cmpu64(const void* _a, const void* _b) { - uint64_t a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); - return UPB_COMPARE_INTEGERS(a, b); -} +static void jsondec_map(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { + upb_Map* map = upb_Message_Mutable(msg, f, d->arena).map; + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); -static int _upb_mapsorter_cmpi32(const void* _a, const void* _b) { - int32_t a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); - return UPB_COMPARE_INTEGERS(a, b); + jsondec_objstart(d); + while (jsondec_objnext(d)) { + upb_MessageValue key, val; + key = jsondec_value(d, key_f); + jsondec_entrysep(d); + val = jsondec_value(d, val_f); + upb_Map_Set(map, key, val, d->arena); + } + jsondec_objend(d); } -static int _upb_mapsorter_cmpu32(const void* _a, const void* _b) { - uint32_t a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); - return UPB_COMPARE_INTEGERS(a, b); +static void jsondec_tomsg(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { + jsondec_object(d, msg, m); + } else { + jsondec_wellknown(d, msg, m); + } } -static int _upb_mapsorter_cmpbool(const void* _a, const void* _b) { - bool a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 1); - return UPB_COMPARE_INTEGERS(a, b); -} +static upb_MessageValue jsondec_msg(jsondec* d, const upb_FieldDef* f) { + const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); + upb_Message* msg = upb_Message_New(m, d->arena); + upb_MessageValue val; -static int _upb_mapsorter_cmpstr(const void* _a, const void* _b) { - upb_StringView a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, UPB_MAPTYPE_STRING); - size_t common_size = UPB_MIN(a.size, b.size); - int cmp = memcmp(a.data, b.data, common_size); - if (cmp) return -cmp; - return UPB_COMPARE_INTEGERS(a.size, b.size); + jsondec_tomsg(d, msg, m); + val.msg_val = msg; + return val; } -#undef UPB_COMPARE_INTEGERS +static void jsondec_field(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_StringView name; + const upb_FieldDef* f; + const upb_FieldDef* preserved; -bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, - const upb_Map* map, _upb_sortedmap* sorted) { - int map_size = _upb_Map_Size(map); - sorted->start = s->size; - sorted->pos = sorted->start; - sorted->end = sorted->start + map_size; + name = jsondec_string(d); + jsondec_entrysep(d); - /* Grow s->entries if necessary. */ - if (sorted->end > s->cap) { - s->cap = _upb_Log2Ceilingsize(sorted->end); - s->entries = realloc(s->entries, s->cap * sizeof(*s->entries)); - if (!s->entries) return false; + if (name.size >= 2 && name.data[0] == '[' && + name.data[name.size - 1] == ']') { + f = upb_DefPool_FindExtensionByNameWithSize(d->symtab, name.data + 1, + name.size - 2); + if (f && upb_FieldDef_ContainingType(f) != m) { + jsondec_errf( + d, "Extension %s extends message %s, but was seen in message %s", + upb_FieldDef_FullName(f), + upb_MessageDef_FullName(upb_FieldDef_ContainingType(f)), + upb_MessageDef_FullName(m)); + } + } else { + f = upb_MessageDef_FindByJsonNameWithSize(m, name.data, name.size); } - s->size = sorted->end; - - /* Copy non-empty entries from the table to s->entries. */ - upb_tabent const** dst = &s->entries[sorted->start]; - const upb_tabent* src = map->table.t.entries; - const upb_tabent* end = src + upb_table_size(&map->table.t); - for (; src < end; src++) { - if (!upb_tabent_isempty(src)) { - *dst = src; - dst++; + if (!f) { + if ((d->options & upb_JsonDecode_IgnoreUnknown) == 0) { + jsondec_errf(d, "No such field: " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(name)); } + jsondec_skipval(d); + return; } - UPB_ASSERT(dst == &s->entries[sorted->end]); - /* Sort entries according to the key type. */ + if (jsondec_peek(d) == JD_NULL && !jsondec_isvalue(f)) { + /* JSON "null" indicates a default value, so no need to set anything. */ + jsondec_null(d); + return; + } - int (*compar)(const void*, const void*); + if (upb_FieldDef_RealContainingOneof(f) && + upb_Message_WhichOneof(msg, upb_FieldDef_ContainingOneof(f))) { + jsondec_err(d, "More than one field for this oneof."); + } - switch (key_type) { - case kUpb_FieldType_Int64: - case kUpb_FieldType_SFixed64: - case kUpb_FieldType_SInt64: - compar = _upb_mapsorter_cmpi64; - break; - case kUpb_FieldType_UInt64: - case kUpb_FieldType_Fixed64: - compar = _upb_mapsorter_cmpu64; - break; - case kUpb_FieldType_Int32: - case kUpb_FieldType_SInt32: - case kUpb_FieldType_SFixed32: - case kUpb_FieldType_Enum: - compar = _upb_mapsorter_cmpi32; - break; - case kUpb_FieldType_UInt32: - case kUpb_FieldType_Fixed32: - compar = _upb_mapsorter_cmpu32; - break; - case kUpb_FieldType_Bool: - compar = _upb_mapsorter_cmpbool; - break; - case kUpb_FieldType_String: - case kUpb_FieldType_Bytes: - compar = _upb_mapsorter_cmpstr; - break; + preserved = d->debug_field; + d->debug_field = f; + + if (upb_FieldDef_IsMap(f)) { + jsondec_map(d, msg, f); + } else if (upb_FieldDef_IsRepeated(f)) { + jsondec_array(d, msg, f); + } else if (upb_FieldDef_IsSubMessage(f)) { + upb_Message* submsg = upb_Message_Mutable(msg, f, d->arena).msg; + const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); + jsondec_tomsg(d, submsg, subm); + } else { + upb_MessageValue val = jsondec_value(d, f); + upb_Message_Set(msg, f, val, d->arena); + } + + d->debug_field = preserved; +} + +static void jsondec_object(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + jsondec_objstart(d); + while (jsondec_objnext(d)) { + jsondec_field(d, msg, m); + } + jsondec_objend(d); +} + +static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + return jsondec_bool(d, f); + case kUpb_CType_Float: + case kUpb_CType_Double: + return jsondec_double(d, f); + case kUpb_CType_UInt32: + case kUpb_CType_UInt64: + return jsondec_uint(d, f); + case kUpb_CType_Int32: + case kUpb_CType_Int64: + return jsondec_int(d, f); + case kUpb_CType_String: + case kUpb_CType_Bytes: + return jsondec_strfield(d, f); + case kUpb_CType_Enum: + return jsondec_enum(d, f); + case kUpb_CType_Message: + return jsondec_msg(d, f); default: UPB_UNREACHABLE(); } - - qsort(&s->entries[sorted->start], map_size, sizeof(*s->entries), compar); - return true; } -/** upb_ExtensionRegistry - * ****************************************************************/ +/* Well-known types ***********************************************************/ + +static int jsondec_tsdigits(jsondec* d, const char** ptr, size_t digits, + const char* after) { + uint64_t val; + const char* p = *ptr; + const char* end = p + digits; + size_t after_len = after ? strlen(after) : 0; -struct upb_ExtensionRegistry { - upb_Arena* arena; - upb_strtable exts; /* Key is upb_MiniTable* concatenated with fieldnum. */ -}; + UPB_ASSERT(digits <= 9); /* int can't overflow. */ -#define EXTREG_KEY_SIZE (sizeof(upb_MiniTable*) + sizeof(uint32_t)) + if (jsondec_buftouint64(d, p, end, &val) != end || + (after_len && memcmp(end, after, after_len) != 0)) { + jsondec_err(d, "Malformed timestamp"); + } -static void extreg_key(char* buf, const upb_MiniTable* l, uint32_t fieldnum) { - memcpy(buf, &l, sizeof(l)); - memcpy(buf + sizeof(l), &fieldnum, sizeof(fieldnum)); -} + UPB_ASSERT(val < INT_MAX); -upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena) { - upb_ExtensionRegistry* r = upb_Arena_Malloc(arena, sizeof(*r)); - if (!r) return NULL; - r->arena = arena; - if (!upb_strtable_init(&r->exts, 8, arena)) return NULL; - return r; + *ptr = end + after_len; + return (int)val; } -bool _upb_extreg_add(upb_ExtensionRegistry* r, - const upb_MiniTable_Extension** e, size_t count) { - char buf[EXTREG_KEY_SIZE]; - const upb_MiniTable_Extension** start = e; - const upb_MiniTable_Extension** end = UPB_PTRADD(e, count); - for (; e < end; e++) { - const upb_MiniTable_Extension* ext = *e; - extreg_key(buf, ext->extendee, ext->field.number); - if (!upb_strtable_insert(&r->exts, buf, EXTREG_KEY_SIZE, - upb_value_constptr(ext), r->arena)) { - goto failure; +static int jsondec_nanos(jsondec* d, const char** ptr, const char* end) { + uint64_t nanos = 0; + const char* p = *ptr; + + if (p != end && *p == '.') { + const char* nano_end = jsondec_buftouint64(d, p + 1, end, &nanos); + int digits = (int)(nano_end - p - 1); + int exp_lg10 = 9 - digits; + if (digits > 9) { + jsondec_err(d, "Too many digits for partial seconds"); } + while (exp_lg10--) nanos *= 10; + *ptr = nano_end; } - return true; -failure: - /* Back out the entries previously added. */ - for (end = e, e = start; e < end; e++) { - const upb_MiniTable_Extension* ext = *e; - extreg_key(buf, ext->extendee, ext->field.number); - upb_strtable_remove2(&r->exts, buf, EXTREG_KEY_SIZE, NULL); - } - return false; -} + UPB_ASSERT(nanos < INT_MAX); -const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r, - const upb_MiniTable* l, - uint32_t num) { - char buf[EXTREG_KEY_SIZE]; - upb_value v; - extreg_key(buf, l, num); - if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, &v)) { - return upb_value_getconstptr(v); - } else { - return NULL; - } + return (int)nanos; } -/** upb/table.c ************************************************************/ -/* - * upb_table Implementation - * - * Implementation is heavily inspired by Lua's ltable.c. - */ - -#include - +/* jsondec_epochdays(1970, 1, 1) == 1970-01-01 == 0. */ +int jsondec_epochdays(int y, int m, int d) { + const uint32_t year_base = 4800; /* Before min year, multiple of 400. */ + const uint32_t m_adj = m - 3; /* March-based month. */ + const uint32_t carry = m_adj > (uint32_t)m ? 1 : 0; + const uint32_t adjust = carry ? 12 : 0; + const uint32_t y_adj = y + year_base - carry; + const uint32_t month_days = ((m_adj + adjust) * 62719 + 769) / 2048; + const uint32_t leap_days = y_adj / 4 - y_adj / 100 + y_adj / 400; + return y_adj * 365 + leap_days + month_days + (d - 1) - 2472632; +} -/* Must be last. */ +static int64_t jsondec_unixtime(int y, int m, int d, int h, int min, int s) { + return (int64_t)jsondec_epochdays(y, m, d) * 86400 + h * 3600 + min * 60 + s; +} -#define UPB_MAXARRSIZE 16 /* 64k. */ +static void jsondec_timestamp(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_MessageValue seconds; + upb_MessageValue nanos; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; -/* From Chromium. */ -#define ARRAY_SIZE(x) \ - ((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x]))))) + if (str.size < 20) goto malformed; -static const double MAX_LOAD = 0.85; + { + /* 1972-01-01T01:00:00 */ + int year = jsondec_tsdigits(d, &ptr, 4, "-"); + int mon = jsondec_tsdigits(d, &ptr, 2, "-"); + int day = jsondec_tsdigits(d, &ptr, 2, "T"); + int hour = jsondec_tsdigits(d, &ptr, 2, ":"); + int min = jsondec_tsdigits(d, &ptr, 2, ":"); + int sec = jsondec_tsdigits(d, &ptr, 2, NULL); -/* The minimum utilization of the array part of a mixed hash/array table. This - * is a speed/memory-usage tradeoff (though it's not straightforward because of - * cache effects). The lower this is, the more memory we'll use. */ -static const double MIN_DENSITY = 0.1; + seconds.int64_val = jsondec_unixtime(year, mon, day, hour, min, sec); + } -static bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; } + nanos.int32_val = jsondec_nanos(d, &ptr, end); -static upb_value _upb_value_val(uint64_t val) { - upb_value ret; - _upb_value_setval(&ret, val); - return ret; -} + { + /* [+-]08:00 or Z */ + int ofs_hour = 0; + int ofs_min = 0; + bool neg = false; -static int log2ceil(uint64_t v) { - int ret = 0; - bool pow2 = is_pow2(v); - while (v >>= 1) ret++; - ret = pow2 ? ret : ret + 1; /* Ceiling. */ - return UPB_MIN(UPB_MAXARRSIZE, ret); -} + if (ptr == end) goto malformed; -char* upb_strdup2(const char* s, size_t len, upb_Arena* a) { - size_t n; - char* p; + switch (*ptr++) { + case '-': + neg = true; + /* fallthrough */ + case '+': + if ((end - ptr) != 5) goto malformed; + ofs_hour = jsondec_tsdigits(d, &ptr, 2, ":"); + ofs_min = jsondec_tsdigits(d, &ptr, 2, NULL); + ofs_min = ((ofs_hour * 60) + ofs_min) * 60; + seconds.int64_val += (neg ? ofs_min : -ofs_min); + break; + case 'Z': + if (ptr != end) goto malformed; + break; + default: + goto malformed; + } + } - /* Prevent overflow errors. */ - if (len == SIZE_MAX) return NULL; - /* Always null-terminate, even if binary data; but don't rely on the input to - * have a null-terminating byte since it may be a raw binary buffer. */ - n = len + 1; - p = upb_Arena_Malloc(a, n); - if (p) { - memcpy(p, s, len); - p[len] = 0; + if (seconds.int64_val < -62135596800) { + jsondec_err(d, "Timestamp out of range"); } - return p; -} -/* A type to represent the lookup key of either a strtable or an inttable. */ -typedef union { - uintptr_t num; - struct { - const char* str; - size_t len; - } str; -} lookupkey_t; + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, + d->arena); + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); + return; -static lookupkey_t strkey2(const char* str, size_t len) { - lookupkey_t k; - k.str.str = str; - k.str.len = len; - return k; +malformed: + jsondec_err(d, "Malformed timestamp"); } -static lookupkey_t intkey(uintptr_t key) { - lookupkey_t k; - k.num = key; - return k; -} +static void jsondec_duration(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_MessageValue seconds; + upb_MessageValue nanos; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; + const int64_t max = (uint64_t)3652500 * 86400; + bool neg = false; -typedef uint32_t hashfunc_t(upb_tabkey key); -typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2); + /* "3.000000001s", "3s", etc. */ + ptr = jsondec_buftoint64(d, ptr, end, &seconds.int64_val, &neg); + nanos.int32_val = jsondec_nanos(d, &ptr, end); -/* Base table (shared code) ***************************************************/ + if (end - ptr != 1 || *ptr != 's') { + jsondec_err(d, "Malformed duration"); + } + + if (seconds.int64_val < -max || seconds.int64_val > max) { + jsondec_err(d, "Duration out of range"); + } -static uint32_t upb_inthash(uintptr_t key) { return (uint32_t)key; } + if (neg) { + nanos.int32_val = -nanos.int32_val; + } -static const upb_tabent* upb_getentry(const upb_table* t, uint32_t hash) { - return t->entries + (hash & t->mask); + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, + d->arena); + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); } -static bool upb_arrhas(upb_tabval key) { return key.val != (uint64_t)-1; } +static void jsondec_listvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(values_f); + upb_Array* values = upb_Message_Mutable(msg, values_f, d->arena).array; -static bool isfull(upb_table* t) { return t->count == t->max_count; } + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + upb_Message* value_msg = upb_Message_New(value_m, d->arena); + upb_MessageValue value; + value.msg_val = value_msg; + upb_Array_Append(values, value, d->arena); + jsondec_wellknownvalue(d, value_msg, value_m); + } + jsondec_arrend(d); +} -static bool init(upb_table* t, uint8_t size_lg2, upb_Arena* a) { - size_t bytes; +static void jsondec_struct(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(value_f); + upb_Map* fields = upb_Message_Mutable(msg, fields_f, d->arena).map; - t->count = 0; - t->size_lg2 = size_lg2; - t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0; - t->max_count = upb_table_size(t) * MAX_LOAD; - bytes = upb_table_size(t) * sizeof(upb_tabent); - if (bytes > 0) { - t->entries = upb_Arena_Malloc(a, bytes); - if (!t->entries) return false; - memset(t->entries, 0, bytes); - } else { - t->entries = NULL; + jsondec_objstart(d); + while (jsondec_objnext(d)) { + upb_MessageValue key, value; + upb_Message* value_msg = upb_Message_New(value_m, d->arena); + key.str_val = jsondec_string(d); + value.msg_val = value_msg; + upb_Map_Set(fields, key, value, d->arena); + jsondec_entrysep(d); + jsondec_wellknownvalue(d, value_msg, value_m); } - return true; + jsondec_objend(d); } -static upb_tabent* emptyent(upb_table* t, upb_tabent* e) { - upb_tabent* begin = t->entries; - upb_tabent* end = begin + upb_table_size(t); - for (e = e + 1; e < end; e++) { - if (upb_tabent_isempty(e)) return e; - } - for (e = begin; e < end; e++) { - if (upb_tabent_isempty(e)) return e; +static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_MessageValue val; + const upb_FieldDef* f; + upb_Message* submsg; + + switch (jsondec_peek(d)) { + case JD_NUMBER: + /* double number_value = 2; */ + f = upb_MessageDef_FindFieldByNumber(m, 2); + val.double_val = jsondec_number(d); + break; + case JD_STRING: + /* string string_value = 3; */ + f = upb_MessageDef_FindFieldByNumber(m, 3); + val.str_val = jsondec_string(d); + break; + case JD_FALSE: + /* bool bool_value = 4; */ + f = upb_MessageDef_FindFieldByNumber(m, 4); + val.bool_val = false; + jsondec_false(d); + break; + case JD_TRUE: + /* bool bool_value = 4; */ + f = upb_MessageDef_FindFieldByNumber(m, 4); + val.bool_val = true; + jsondec_true(d); + break; + case JD_NULL: + /* NullValue null_value = 1; */ + f = upb_MessageDef_FindFieldByNumber(m, 1); + val.int32_val = 0; + jsondec_null(d); + break; + /* Note: these cases return, because upb_Message_Mutable() is enough. */ + case JD_OBJECT: + /* Struct struct_value = 5; */ + f = upb_MessageDef_FindFieldByNumber(m, 5); + submsg = upb_Message_Mutable(msg, f, d->arena).msg; + jsondec_struct(d, submsg, upb_FieldDef_MessageSubDef(f)); + return; + case JD_ARRAY: + /* ListValue list_value = 6; */ + f = upb_MessageDef_FindFieldByNumber(m, 6); + submsg = upb_Message_Mutable(msg, f, d->arena).msg; + jsondec_listvalue(d, submsg, upb_FieldDef_MessageSubDef(f)); + return; + default: + UPB_UNREACHABLE(); } - UPB_ASSERT(false); - return NULL; -} -static upb_tabent* getentry_mutable(upb_table* t, uint32_t hash) { - return (upb_tabent*)upb_getentry(t, hash); + upb_Message_Set(msg, f, val, d->arena); } -static const upb_tabent* findentry(const upb_table* t, lookupkey_t key, - uint32_t hash, eqlfunc_t* eql) { - const upb_tabent* e; +static upb_StringView jsondec_mask(jsondec* d, const char* buf, + const char* end) { + /* FieldMask fields grow due to inserted '_' characters, so we can't do the + * transform in place. */ + const char* ptr = buf; + upb_StringView ret; + char* out; - if (t->size_lg2 == 0) return NULL; - e = upb_getentry(t, hash); - if (upb_tabent_isempty(e)) return NULL; - while (1) { - if (eql(e->key, key)) return e; - if ((e = e->next) == NULL) return NULL; + ret.size = end - ptr; + while (ptr < end) { + ret.size += (*ptr >= 'A' && *ptr <= 'Z'); + ptr++; } -} -static upb_tabent* findentry_mutable(upb_table* t, lookupkey_t key, - uint32_t hash, eqlfunc_t* eql) { - return (upb_tabent*)findentry(t, key, hash, eql); + out = upb_Arena_Malloc(d->arena, ret.size); + ptr = buf; + ret.data = out; + + while (ptr < end) { + char ch = *ptr++; + if (ch >= 'A' && ch <= 'Z') { + *out++ = '_'; + *out++ = ch + 32; + } else if (ch == '_') { + jsondec_err(d, "field mask may not contain '_'"); + } else { + *out++ = ch; + } + } + + return ret; } -static bool lookup(const upb_table* t, lookupkey_t key, upb_value* v, - uint32_t hash, eqlfunc_t* eql) { - const upb_tabent* e = findentry(t, key, hash, eql); - if (e) { - if (v) { - _upb_value_setval(v, e->val.val); +static void jsondec_fieldmask(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + /* repeated string paths = 1; */ + const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_Array* arr = upb_Message_Mutable(msg, paths_f, d->arena).array; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; + upb_MessageValue val; + + while (ptr < end) { + const char* elem_end = memchr(ptr, ',', end - ptr); + if (elem_end) { + val.str_val = jsondec_mask(d, ptr, elem_end); + ptr = elem_end + 1; + } else { + val.str_val = jsondec_mask(d, ptr, end); + ptr = end; } - return true; + upb_Array_Append(arr, val, d->arena); + } +} + +static void jsondec_anyfield(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { + /* For regular types: {"@type": "[user type]", "f1": , "f2": } + * where f1, f2, etc. are the normal fields of this type. */ + jsondec_field(d, msg, m); } else { - return false; + /* For well-known types: {"@type": "[well-known type]", "value": } + * where is whatever encoding the WKT normally uses. */ + upb_StringView str = jsondec_string(d); + jsondec_entrysep(d); + if (!jsondec_streql(str, "value")) { + jsondec_err(d, "Key for well-known type must be 'value'"); + } + jsondec_wellknown(d, msg, m); } } -/* The given key must not already exist in the table. */ -static void insert(upb_table* t, lookupkey_t key, upb_tabkey tabkey, - upb_value val, uint32_t hash, hashfunc_t* hashfunc, - eqlfunc_t* eql) { - upb_tabent* mainpos_e; - upb_tabent* our_e; +static const upb_MessageDef* jsondec_typeurl(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* type_m; + upb_StringView type_url = jsondec_string(d); + const char* end = type_url.data + type_url.size; + const char* ptr = end; + upb_MessageValue val; - UPB_ASSERT(findentry(t, key, hash, eql) == NULL); + val.str_val = type_url; + upb_Message_Set(msg, type_url_f, val, d->arena); - t->count++; - mainpos_e = getentry_mutable(t, hash); - our_e = mainpos_e; + /* Find message name after the last '/' */ + while (ptr > type_url.data && *--ptr != '/') { + } - if (upb_tabent_isempty(mainpos_e)) { - /* Our main position is empty; use it. */ - our_e->next = NULL; - } else { - /* Collision. */ - upb_tabent* new_e = emptyent(t, mainpos_e); - /* Head of collider's chain. */ - upb_tabent* chain = getentry_mutable(t, hashfunc(mainpos_e->key)); - if (chain == mainpos_e) { - /* Existing ent is in its main position (it has the same hash as us, and - * is the head of our chain). Insert to new ent and append to this chain. - */ - new_e->next = mainpos_e->next; - mainpos_e->next = new_e; - our_e = new_e; - } else { - /* Existing ent is not in its main position (it is a node in some other - * chain). This implies that no existing ent in the table has our hash. - * Evict it (updating its chain) and use its ent for head of our chain. */ - *new_e = *mainpos_e; /* copies next. */ - while (chain->next != mainpos_e) { - chain = (upb_tabent*)chain->next; - UPB_ASSERT(chain); - } - chain->next = new_e; - our_e = mainpos_e; - our_e->next = NULL; - } + if (ptr == type_url.data || ptr == end) { + jsondec_err(d, "Type url must have at least one '/' and non-empty host"); } - our_e->key = tabkey; - our_e->val.val = val.val; - UPB_ASSERT(findentry(t, key, hash, eql) == our_e); + + ptr++; + type_m = upb_DefPool_FindMessageByNameWithSize(d->symtab, ptr, end - ptr); + + if (!type_m) { + jsondec_err(d, "Type was not found"); + } + + return type_m; } -static bool rm(upb_table* t, lookupkey_t key, upb_value* val, - upb_tabkey* removed, uint32_t hash, eqlfunc_t* eql) { - upb_tabent* chain = getentry_mutable(t, hash); - if (upb_tabent_isempty(chain)) return false; - if (eql(chain->key, key)) { - /* Element to remove is at the head of its chain. */ - t->count--; - if (val) _upb_value_setval(val, chain->val.val); - if (removed) *removed = chain->key; - if (chain->next) { - upb_tabent* move = (upb_tabent*)chain->next; - *chain = *move; - move->key = 0; /* Make the slot empty. */ +static void jsondec_any(jsondec* d, upb_Message* msg, const upb_MessageDef* m) { + /* string type_url = 1; + * bytes value = 2; */ + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); + upb_Message* any_msg; + const upb_MessageDef* any_m = NULL; + const char* pre_type_data = NULL; + const char* pre_type_end = NULL; + upb_MessageValue encoded; + + jsondec_objstart(d); + + /* Scan looking for "@type", which is not necessarily first. */ + while (!any_m && jsondec_objnext(d)) { + const char* start = d->ptr; + upb_StringView name = jsondec_string(d); + jsondec_entrysep(d); + if (jsondec_streql(name, "@type")) { + any_m = jsondec_typeurl(d, msg, m); + if (pre_type_data) { + pre_type_end = start; + while (*pre_type_end != ',') pre_type_end--; + } } else { - chain->key = 0; /* Make the slot empty. */ - } - return true; - } else { - /* Element to remove is either in a non-head position or not in the - * table. */ - while (chain->next && !eql(chain->next->key, key)) { - chain = (upb_tabent*)chain->next; + if (!pre_type_data) pre_type_data = start; + jsondec_skipval(d); } - if (chain->next) { - /* Found element to remove. */ - upb_tabent* rm = (upb_tabent*)chain->next; - t->count--; - if (val) _upb_value_setval(val, chain->next->val.val); - if (removed) *removed = rm->key; - rm->key = 0; /* Make the slot empty. */ - chain->next = rm->next; - return true; - } else { - /* Element to remove is not in the table. */ - return false; + } + + if (!any_m) { + jsondec_err(d, "Any object didn't contain a '@type' field"); + } + + any_msg = upb_Message_New(any_m, d->arena); + + if (pre_type_data) { + size_t len = pre_type_end - pre_type_data + 1; + char* tmp = upb_Arena_Malloc(d->arena, len); + const char* saved_ptr = d->ptr; + const char* saved_end = d->end; + memcpy(tmp, pre_type_data, len - 1); + tmp[len - 1] = '}'; + d->ptr = tmp; + d->end = tmp + len; + d->is_first = true; + while (jsondec_objnext(d)) { + jsondec_anyfield(d, any_msg, any_m); } + d->ptr = saved_ptr; + d->end = saved_end; + } + + while (jsondec_objnext(d)) { + jsondec_anyfield(d, any_msg, any_m); } + + jsondec_objend(d); + + upb_EncodeStatus status = + upb_Encode(any_msg, upb_MessageDef_MiniTable(any_m), 0, d->arena, + (char**)&encoded.str_val.data, &encoded.str_val.size); + // TODO(b/235839510): We should fail gracefully here on a bad return status. + UPB_ASSERT(status == kUpb_EncodeStatus_Ok); + upb_Message_Set(msg, value_f, encoded, d->arena); } -static size_t next(const upb_table* t, size_t i) { - do { - if (++i >= upb_table_size(t)) return SIZE_MAX - 1; /* Distinct from -1. */ - } while (upb_tabent_isempty(&t->entries[i])); +static void jsondec_wrapper(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_MessageValue val = jsondec_value(d, value_f); + upb_Message_Set(msg, value_f, val, d->arena); +} - return i; +static void jsondec_wellknown(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + switch (upb_MessageDef_WellKnownType(m)) { + case kUpb_WellKnown_Any: + jsondec_any(d, msg, m); + break; + case kUpb_WellKnown_FieldMask: + jsondec_fieldmask(d, msg, m); + break; + case kUpb_WellKnown_Duration: + jsondec_duration(d, msg, m); + break; + case kUpb_WellKnown_Timestamp: + jsondec_timestamp(d, msg, m); + break; + case kUpb_WellKnown_Value: + jsondec_wellknownvalue(d, msg, m); + break; + case kUpb_WellKnown_ListValue: + jsondec_listvalue(d, msg, m); + break; + case kUpb_WellKnown_Struct: + jsondec_struct(d, msg, m); + break; + case kUpb_WellKnown_DoubleValue: + case kUpb_WellKnown_FloatValue: + case kUpb_WellKnown_Int64Value: + case kUpb_WellKnown_UInt64Value: + case kUpb_WellKnown_Int32Value: + case kUpb_WellKnown_UInt32Value: + case kUpb_WellKnown_StringValue: + case kUpb_WellKnown_BytesValue: + case kUpb_WellKnown_BoolValue: + jsondec_wrapper(d, msg, m); + break; + default: + UPB_UNREACHABLE(); + } } -static size_t begin(const upb_table* t) { return next(t, -1); } +bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, + const upb_MessageDef* m, const upb_DefPool* symtab, + int options, upb_Arena* arena, upb_Status* status) { + jsondec d; -/* upb_strtable ***************************************************************/ + if (size == 0) return true; -/* A simple "subclass" of upb_table that only adds a hash function for strings. - */ + d.ptr = buf; + d.end = buf + size; + d.arena = arena; + d.symtab = symtab; + d.status = status; + d.options = options; + d.depth = 64; + d.line = 1; + d.line_begin = d.ptr; + d.debug_field = NULL; + d.is_first = false; -static upb_tabkey strcopy(lookupkey_t k2, upb_Arena* a) { - uint32_t len = (uint32_t)k2.str.len; - char* str = upb_Arena_Malloc(a, k2.str.len + sizeof(uint32_t) + 1); - if (str == NULL) return 0; - memcpy(str, &len, sizeof(uint32_t)); - if (k2.str.len) memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len); - str[sizeof(uint32_t) + k2.str.len] = '\0'; - return (uintptr_t)str; + if (UPB_SETJMP(d.err)) return false; + + jsondec_tomsg(&d, msg, m); + return true; } -/* Adapted from ABSL's wyhash. */ -static uint64_t UnalignedLoad64(const void* p) { - uint64_t val; - memcpy(&val, p, 8); - return val; -} +#include +#include +#include +#include +#include +#include +#include -static uint32_t UnalignedLoad32(const void* p) { - uint32_t val; - memcpy(&val, p, 4); - return val; -} -#if defined(_MSC_VER) && defined(_M_X64) -#include -#endif +// Must be last. -/* Computes a * b, returning the low 64 bits of the result and storing the high - * 64 bits in |*high|. */ -static uint64_t upb_umul128(uint64_t v0, uint64_t v1, uint64_t* out_high) { -#ifdef __SIZEOF_INT128__ - __uint128_t p = v0; - p *= v1; - *out_high = (uint64_t)(p >> 64); - return (uint64_t)p; -#elif defined(_MSC_VER) && defined(_M_X64) - return _umul128(v0, v1, out_high); -#else - uint64_t a32 = v0 >> 32; - uint64_t a00 = v0 & 0xffffffff; - uint64_t b32 = v1 >> 32; - uint64_t b00 = v1 & 0xffffffff; - uint64_t high = a32 * b32; - uint64_t low = a00 * b00; - uint64_t mid1 = a32 * b00; - uint64_t mid2 = a00 * b32; - low += (mid1 << 32) + (mid2 << 32); - // Omit carry bit, for mixing we do not care about exact numerical precision. - high += (mid1 >> 32) + (mid2 >> 32); - *out_high = high; - return low; -#endif +typedef struct { + char *buf, *ptr, *end; + size_t overflow; + int indent_depth; + int options; + const upb_DefPool* ext_pool; + jmp_buf err; + upb_Status* status; + upb_Arena* arena; +} jsonenc; + +static void jsonenc_msg(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); +static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f); +static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); +static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m, bool first); +static void jsonenc_value(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); + +UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) { + upb_Status_SetErrorMessage(e->status, msg); + longjmp(e->err, 1); +} + +UPB_PRINTF(2, 3) +UPB_NORETURN static void jsonenc_errf(jsonenc* e, const char* fmt, ...) { + va_list argp; + va_start(argp, fmt); + upb_Status_VSetErrorFormat(e->status, fmt, argp); + va_end(argp); + longjmp(e->err, 1); } -static uint64_t WyhashMix(uint64_t v0, uint64_t v1) { - uint64_t high; - uint64_t low = upb_umul128(v0, v1, &high); - return low ^ high; +static upb_Arena* jsonenc_arena(jsonenc* e) { + /* Create lazily, since it's only needed for Any */ + if (!e->arena) { + e->arena = upb_Arena_New(); + } + return e->arena; } -static uint64_t Wyhash(const void* data, size_t len, uint64_t seed, - const uint64_t salt[]) { - const uint8_t* ptr = (const uint8_t*)data; - uint64_t starting_length = (uint64_t)len; - uint64_t current_state = seed ^ salt[0]; +static void jsonenc_putbytes(jsonenc* e, const void* data, size_t len) { + size_t have = e->end - e->ptr; + if (UPB_LIKELY(have >= len)) { + memcpy(e->ptr, data, len); + e->ptr += len; + } else { + if (have) { + memcpy(e->ptr, data, have); + e->ptr += have; + } + e->overflow += (len - have); + } +} - if (len > 64) { - // If we have more than 64 bytes, we're going to handle chunks of 64 - // bytes at a time. We're going to build up two separate hash states - // which we will then hash together. - uint64_t duplicated_state = current_state; +static void jsonenc_putstr(jsonenc* e, const char* str) { + jsonenc_putbytes(e, str, strlen(str)); +} - do { - uint64_t a = UnalignedLoad64(ptr); - uint64_t b = UnalignedLoad64(ptr + 8); - uint64_t c = UnalignedLoad64(ptr + 16); - uint64_t d = UnalignedLoad64(ptr + 24); - uint64_t e = UnalignedLoad64(ptr + 32); - uint64_t f = UnalignedLoad64(ptr + 40); - uint64_t g = UnalignedLoad64(ptr + 48); - uint64_t h = UnalignedLoad64(ptr + 56); +UPB_PRINTF(2, 3) +static void jsonenc_printf(jsonenc* e, const char* fmt, ...) { + size_t n; + size_t have = e->end - e->ptr; + va_list args; - uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state); - uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state); - current_state = (cs0 ^ cs1); + va_start(args, fmt); + n = _upb_vsnprintf(e->ptr, have, fmt, args); + va_end(args); - uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state); - uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state); - duplicated_state = (ds0 ^ ds1); + if (UPB_LIKELY(have > n)) { + e->ptr += n; + } else { + e->ptr = UPB_PTRADD(e->ptr, have); + e->overflow += (n - have); + } +} - ptr += 64; - len -= 64; - } while (len > 64); +static void jsonenc_nanos(jsonenc* e, int32_t nanos) { + int digits = 9; - current_state = current_state ^ duplicated_state; + if (nanos == 0) return; + if (nanos < 0 || nanos >= 1000000000) { + jsonenc_err(e, "error formatting timestamp as JSON: invalid nanos"); } - // We now have a data `ptr` with at most 64 bytes and the current state - // of the hashing state machine stored in current_state. - while (len > 16) { - uint64_t a = UnalignedLoad64(ptr); - uint64_t b = UnalignedLoad64(ptr + 8); + while (nanos % 1000 == 0) { + nanos /= 1000; + digits -= 3; + } - current_state = WyhashMix(a ^ salt[1], b ^ current_state); + jsonenc_printf(e, ".%.*" PRId32, digits, nanos); +} - ptr += 16; - len -= 16; - } +static void jsonenc_timestamp(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); + int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; + int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; + int L, N, I, J, K, hour, min, sec; - // We now have a data `ptr` with at most 16 bytes. - uint64_t a = 0; - uint64_t b = 0; - if (len > 8) { - // When we have at least 9 and at most 16 bytes, set A to the first 64 - // bits of the input and B to the last 64 bits of the input. Yes, they will - // overlap in the middle if we are working with less than the full 16 - // bytes. - a = UnalignedLoad64(ptr); - b = UnalignedLoad64(ptr + len - 8); - } else if (len > 3) { - // If we have at least 4 and at most 8 bytes, set A to the first 32 - // bits and B to the last 32 bits. - a = UnalignedLoad32(ptr); - b = UnalignedLoad32(ptr + len - 4); - } else if (len > 0) { - // If we have at least 1 and at most 3 bytes, read all of the provided - // bits into A, with some adjustments. - a = ((ptr[0] << 16) | (ptr[len >> 1] << 8) | ptr[len - 1]); - b = 0; - } else { - a = 0; - b = 0; + if (seconds < -62135596800) { + jsonenc_err(e, + "error formatting timestamp as JSON: minimum acceptable value " + "is 0001-01-01T00:00:00Z"); + } else if (seconds > 253402300799) { + jsonenc_err(e, + "error formatting timestamp as JSON: maximum acceptable value " + "is 9999-12-31T23:59:59Z"); } - uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state); - uint64_t z = salt[1] ^ starting_length; - return WyhashMix(w, z); -} + /* Julian Day -> Y/M/D, Algorithm from: + * Fliegel, H. F., and Van Flandern, T. C., "A Machine Algorithm for + * Processing Calendar Dates," Communications of the Association of + * Computing Machines, vol. 11 (1968), p. 657. */ + seconds += 62135596800; // Ensure seconds is positive. + L = (int)(seconds / 86400) - 719162 + 68569 + 2440588; + N = 4 * L / 146097; + L = L - (146097 * N + 3) / 4; + I = 4000 * (L + 1) / 1461001; + L = L - 1461 * I / 4 + 31; + J = 80 * L / 2447; + K = L - 2447 * J / 80; + L = J / 11; + J = J + 2 - 12 * L; + I = 100 * (N - 49) + I + L; -const uint64_t kWyhashSalt[5] = { - 0x243F6A8885A308D3ULL, 0x13198A2E03707344ULL, 0xA4093822299F31D0ULL, - 0x082EFA98EC4E6C89ULL, 0x452821E638D01377ULL, -}; + sec = seconds % 60; + min = (seconds / 60) % 60; + hour = (seconds / 3600) % 24; -static uint32_t table_hash(const char* p, size_t n) { - return Wyhash(p, n, 0, kWyhashSalt); + jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec); + jsonenc_nanos(e, nanos); + jsonenc_putstr(e, "Z\""); } -static uint32_t strhash(upb_tabkey key) { - uint32_t len; - char* str = upb_tabstr(key, &len); - return table_hash(str, len); -} +static void jsonenc_duration(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); + int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; + int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; + bool negative = false; -static bool streql(upb_tabkey k1, lookupkey_t k2) { - uint32_t len; - char* str = upb_tabstr(k1, &len); - return len == k2.str.len && (len == 0 || memcmp(str, k2.str.str, len) == 0); -} + if (seconds > 315576000000 || seconds < -315576000000 || + (seconds != 0 && nanos != 0 && (seconds < 0) != (nanos < 0))) { + jsonenc_err(e, "bad duration"); + } -bool upb_strtable_init(upb_strtable* t, size_t expected_size, upb_Arena* a) { - // Multiply by approximate reciprocal of MAX_LOAD (0.85), with pow2 - // denominator. - size_t need_entries = (expected_size + 1) * 1204 / 1024; - UPB_ASSERT(need_entries >= expected_size * 0.85); - int size_lg2 = _upb_Log2Ceiling(need_entries); - return init(&t->t, size_lg2, a); + if (seconds < 0) { + negative = true; + seconds = -seconds; + } + if (nanos < 0) { + negative = true; + nanos = -nanos; + } + + jsonenc_putstr(e, "\""); + if (negative) { + jsonenc_putstr(e, "-"); + } + jsonenc_printf(e, "%" PRId64, seconds); + jsonenc_nanos(e, nanos); + jsonenc_putstr(e, "s\""); } -void upb_strtable_clear(upb_strtable* t) { - size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent); - t->t.count = 0; - memset((char*)t->t.entries, 0, bytes); +static void jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) { + const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f); + + if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) { + jsonenc_putstr(e, "null"); + } else { + const upb_EnumValueDef* ev = + (e->options & upb_JsonEncode_FormatEnumsAsIntegers) + ? NULL + : upb_EnumDef_FindValueByNumber(e_def, val); + + if (ev) { + jsonenc_printf(e, "\"%s\"", upb_EnumValueDef_Name(ev)); + } else { + jsonenc_printf(e, "%" PRId32, val); + } + } } -bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a) { - upb_strtable new_table; - upb_strtable_iter i; +static void jsonenc_bytes(jsonenc* e, upb_StringView str) { + /* This is the regular base64, not the "web-safe" version. */ + static const char base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + const unsigned char* ptr = (unsigned char*)str.data; + const unsigned char* end = UPB_PTRADD(ptr, str.size); + char buf[4]; - if (!init(&new_table.t, size_lg2, a)) return false; - upb_strtable_begin(&i, t); - for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { - upb_StringView key = upb_strtable_iter_key(&i); - upb_strtable_insert(&new_table, key.data, key.size, - upb_strtable_iter_value(&i), a); + jsonenc_putstr(e, "\""); + + while (end - ptr >= 3) { + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; + buf[2] = base64[((ptr[1] & 0xf) << 2) | (ptr[2] >> 6)]; + buf[3] = base64[ptr[2] & 0x3f]; + jsonenc_putbytes(e, buf, 4); + ptr += 3; + } + + switch (end - ptr) { + case 2: + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; + buf[2] = base64[(ptr[1] & 0xf) << 2]; + buf[3] = '='; + jsonenc_putbytes(e, buf, 4); + break; + case 1: + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4)]; + buf[2] = '='; + buf[3] = '='; + jsonenc_putbytes(e, buf, 4); + break; } - *t = new_table; - return true; + + jsonenc_putstr(e, "\""); } -bool upb_strtable_insert(upb_strtable* t, const char* k, size_t len, - upb_value v, upb_Arena* a) { - lookupkey_t key; - upb_tabkey tabkey; - uint32_t hash; +static void jsonenc_stringbody(jsonenc* e, upb_StringView str) { + const char* ptr = str.data; + const char* end = UPB_PTRADD(ptr, str.size); - if (isfull(&t->t)) { - /* Need to resize. New table of double the size, add old elements to it. */ - if (!upb_strtable_resize(t, t->t.size_lg2 + 1, a)) { - return false; + while (ptr < end) { + switch (*ptr) { + case '\n': + jsonenc_putstr(e, "\\n"); + break; + case '\r': + jsonenc_putstr(e, "\\r"); + break; + case '\t': + jsonenc_putstr(e, "\\t"); + break; + case '\"': + jsonenc_putstr(e, "\\\""); + break; + case '\f': + jsonenc_putstr(e, "\\f"); + break; + case '\b': + jsonenc_putstr(e, "\\b"); + break; + case '\\': + jsonenc_putstr(e, "\\\\"); + break; + default: + if ((uint8_t)*ptr < 0x20) { + jsonenc_printf(e, "\\u%04x", (int)(uint8_t)*ptr); + } else { + /* This could be a non-ASCII byte. We rely on the string being valid + * UTF-8. */ + jsonenc_putbytes(e, ptr, 1); + } + break; } + ptr++; } +} - key = strkey2(k, len); - tabkey = strcopy(key, a); - if (tabkey == 0) return false; +static void jsonenc_string(jsonenc* e, upb_StringView str) { + jsonenc_putstr(e, "\""); + jsonenc_stringbody(e, str); + jsonenc_putstr(e, "\""); +} - hash = table_hash(key.str.str, key.str.len); - insert(&t->t, key, tabkey, v, hash, &strhash, &streql); +static bool upb_JsonEncode_HandleSpecialDoubles(jsonenc* e, double val) { + if (val == INFINITY) { + jsonenc_putstr(e, "\"Infinity\""); + } else if (val == -INFINITY) { + jsonenc_putstr(e, "\"-Infinity\""); + } else if (val != val) { + jsonenc_putstr(e, "\"NaN\""); + } else { + return false; + } return true; } -bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, - upb_value* v) { - uint32_t hash = table_hash(key, len); - return lookup(&t->t, strkey2(key, len), v, hash, &streql); +static void upb_JsonEncode_Double(jsonenc* e, double val) { + if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; + char buf[32]; + _upb_EncodeRoundTripDouble(val, buf, sizeof(buf)); + jsonenc_putstr(e, buf); } -bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, - upb_value* val) { - uint32_t hash = table_hash(key, len); - upb_tabkey tabkey; - return rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql); +static void upb_JsonEncode_Float(jsonenc* e, float val) { + if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; + char buf[32]; + _upb_EncodeRoundTripFloat(val, buf, sizeof(buf)); + jsonenc_putstr(e, buf); } -/* Iteration */ - -void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t) { - i->t = t; - i->index = begin(&t->t); +static void jsonenc_wrapper(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_MessageValue val = upb_Message_Get(msg, val_f); + jsonenc_scalar(e, val, val_f); } -void upb_strtable_next(upb_strtable_iter* i) { - i->index = next(&i->t->t, i->index); -} +static const upb_MessageDef* jsonenc_getanymsg(jsonenc* e, + upb_StringView type_url) { + /* Find last '/', if any. */ + const char* end = type_url.data + type_url.size; + const char* ptr = end; + const upb_MessageDef* ret; -bool upb_strtable_done(const upb_strtable_iter* i) { - if (!i->t) return true; - return i->index >= upb_table_size(&i->t->t) || - upb_tabent_isempty(str_tabent(i)); -} + if (!e->ext_pool) { + jsonenc_err(e, "Tried to encode Any, but no symtab was provided"); + } -upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i) { - upb_StringView key; - uint32_t len; - UPB_ASSERT(!upb_strtable_done(i)); - key.data = upb_tabstr(str_tabent(i)->key, &len); - key.size = len; - return key; -} + if (type_url.size == 0) goto badurl; -upb_value upb_strtable_iter_value(const upb_strtable_iter* i) { - UPB_ASSERT(!upb_strtable_done(i)); - return _upb_value_val(str_tabent(i)->val.val); -} + while (true) { + if (--ptr == type_url.data) { + /* Type URL must contain at least one '/', with host before. */ + goto badurl; + } + if (*ptr == '/') { + ptr++; + break; + } + } -void upb_strtable_iter_setdone(upb_strtable_iter* i) { - i->t = NULL; - i->index = SIZE_MAX; -} + ret = upb_DefPool_FindMessageByNameWithSize(e->ext_pool, ptr, end - ptr); -bool upb_strtable_iter_isequal(const upb_strtable_iter* i1, - const upb_strtable_iter* i2) { - if (upb_strtable_done(i1) && upb_strtable_done(i2)) return true; - return i1->t == i2->t && i1->index == i2->index; + if (!ret) { + jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr); + } + + return ret; + +badurl: + jsonenc_errf(e, "Bad type URL: " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(type_url)); } -/* upb_inttable ***************************************************************/ +static void jsonenc_any(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); + upb_StringView type_url = upb_Message_Get(msg, type_url_f).str_val; + upb_StringView value = upb_Message_Get(msg, value_f).str_val; + const upb_MessageDef* any_m = jsonenc_getanymsg(e, type_url); + const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m); + upb_Arena* arena = jsonenc_arena(e); + upb_Message* any = upb_Message_New(any_m, arena); -/* For inttables we use a hybrid structure where small keys are kept in an - * array and large keys are put in the hash table. */ + if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + jsonenc_err(e, "Error decoding message in Any"); + } -static uint32_t inthash(upb_tabkey key) { return upb_inthash(key); } + jsonenc_putstr(e, "{\"@type\":"); + jsonenc_string(e, type_url); -static bool inteql(upb_tabkey k1, lookupkey_t k2) { return k1 == k2.num; } + if (upb_MessageDef_WellKnownType(any_m) == kUpb_WellKnown_Unspecified) { + /* Regular messages: {"@type": "...","foo": 1, "bar": 2} */ + jsonenc_msgfields(e, any, any_m, false); + } else { + /* Well-known type: {"@type": "...","value": } */ + jsonenc_putstr(e, ",\"value\":"); + jsonenc_msgfield(e, any, any_m); + } -static upb_tabval* mutable_array(upb_inttable* t) { - return (upb_tabval*)t->array; + jsonenc_putstr(e, "}"); } -static upb_tabval* inttable_val(upb_inttable* t, uintptr_t key) { - if (key < t->array_size) { - return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL; +static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) { + if (*first) { + *first = false; } else { - upb_tabent* e = - findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql); - return e ? &e->val : NULL; + jsonenc_putstr(e, str); } } -static const upb_tabval* inttable_val_const(const upb_inttable* t, - uintptr_t key) { - return inttable_val((upb_inttable*)t, key); -} +static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) { + const char* ptr = path.data; + const char* end = ptr + path.size; -size_t upb_inttable_count(const upb_inttable* t) { - return t->t.count + t->array_count; -} + while (ptr < end) { + char ch = *ptr; -static void check(upb_inttable* t) { - UPB_UNUSED(t); -#if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG) - { - /* This check is very expensive (makes inserts/deletes O(N)). */ - size_t count = 0; - upb_inttable_iter i; - upb_inttable_begin(&i, t); - for (; !upb_inttable_done(&i); upb_inttable_next(&i), count++) { - UPB_ASSERT(upb_inttable_lookup(t, upb_inttable_iter_key(&i), NULL)); + if (ch >= 'A' && ch <= 'Z') { + jsonenc_err(e, "Field mask element may not have upper-case letter."); + } else if (ch == '_') { + if (ptr == end - 1 || *(ptr + 1) < 'a' || *(ptr + 1) > 'z') { + jsonenc_err(e, "Underscore must be followed by a lowercase letter."); + } + ch = *++ptr - 32; } - UPB_ASSERT(count == upb_inttable_count(t)); - } -#endif -} - -bool upb_inttable_sizedinit(upb_inttable* t, size_t asize, int hsize_lg2, - upb_Arena* a) { - size_t array_bytes; - if (!init(&t->t, hsize_lg2, a)) return false; - /* Always make the array part at least 1 long, so that we know key 0 - * won't be in the hash part, which simplifies things. */ - t->array_size = UPB_MAX(1, asize); - t->array_count = 0; - array_bytes = t->array_size * sizeof(upb_value); - t->array = upb_Arena_Malloc(a, array_bytes); - if (!t->array) { - return false; + jsonenc_putbytes(e, &ch, 1); + ptr++; } - memset(mutable_array(t), 0xff, array_bytes); - check(t); - return true; } -bool upb_inttable_init(upb_inttable* t, upb_Arena* a) { - return upb_inttable_sizedinit(t, 0, 4, a); -} +static void jsonenc_fieldmask(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_Array* paths = upb_Message_Get(msg, paths_f).array_val; + bool first = true; + size_t i, n = 0; -bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, - upb_Arena* a) { - upb_tabval tabval; - tabval.val = val.val; - UPB_ASSERT( - upb_arrhas(tabval)); /* This will reject (uint64_t)-1. Fix this. */ + if (paths) n = upb_Array_Size(paths); - if (key < t->array_size) { - UPB_ASSERT(!upb_arrhas(t->array[key])); - t->array_count++; - mutable_array(t)[key].val = val.val; - } else { - if (isfull(&t->t)) { - /* Need to resize the hash part, but we re-use the array part. */ - size_t i; - upb_table new_table; + jsonenc_putstr(e, "\""); - if (!init(&new_table, t->t.size_lg2 + 1, a)) { - return false; - } + for (i = 0; i < n; i++) { + jsonenc_putsep(e, ",", &first); + jsonenc_fieldpath(e, upb_Array_Get(paths, i).str_val); + } - for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) { - const upb_tabent* e = &t->t.entries[i]; - uint32_t hash; - upb_value v; + jsonenc_putstr(e, "\""); +} - _upb_value_setval(&v, e->val.val); - hash = upb_inthash(e->key); - insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql); - } +static void jsonenc_struct(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_Map* fields = upb_Message_Get(msg, fields_f).map_val; + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + size_t iter = kUpb_Map_Begin; + bool first = true; - UPB_ASSERT(t->t.count == new_table.count); + jsonenc_putstr(e, "{"); - t->t = new_table; + if (fields) { + while (upb_MapIterator_Next(fields, &iter)) { + upb_MessageValue key = upb_MapIterator_Key(fields, iter); + upb_MessageValue val = upb_MapIterator_Value(fields, iter); + + jsonenc_putsep(e, ",", &first); + jsonenc_string(e, key.str_val); + jsonenc_putstr(e, ":"); + jsonenc_value(e, val.msg_val, upb_FieldDef_MessageSubDef(value_f)); } - insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql); } - check(t); - return true; -} -bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v) { - const upb_tabval* table_v = inttable_val_const(t, key); - if (!table_v) return false; - if (v) _upb_value_setval(v, table_v->val); - return true; + jsonenc_putstr(e, "}"); } -bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val) { - upb_tabval* table_v = inttable_val(t, key); - if (!table_v) return false; - table_v->val = val.val; - return true; -} +static void jsonenc_listvalue(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* values_m = upb_FieldDef_MessageSubDef(values_f); + const upb_Array* values = upb_Message_Get(msg, values_f).array_val; + size_t i; + bool first = true; -bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val) { - bool success; - if (key < t->array_size) { - if (upb_arrhas(t->array[key])) { - upb_tabval empty = UPB_TABVALUE_EMPTY_INIT; - t->array_count--; - if (val) { - _upb_value_setval(val, t->array[key].val); - } - mutable_array(t)[key] = empty; - success = true; - } else { - success = false; + jsonenc_putstr(e, "["); + + if (values) { + const size_t size = upb_Array_Size(values); + for (i = 0; i < size; i++) { + upb_MessageValue elem = upb_Array_Get(values, i); + + jsonenc_putsep(e, ",", &first); + jsonenc_value(e, elem.msg_val, values_m); } - } else { - success = rm(&t->t, intkey(key), val, NULL, upb_inthash(key), &inteql); } - check(t); - return success; + + jsonenc_putstr(e, "]"); } -void upb_inttable_compact(upb_inttable* t, upb_Arena* a) { - /* A power-of-two histogram of the table keys. */ - size_t counts[UPB_MAXARRSIZE + 1] = {0}; +static void jsonenc_value(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + /* TODO(haberman): do we want a reflection method to get oneof case? */ + size_t iter = kUpb_Message_Begin; + const upb_FieldDef* f; + upb_MessageValue val; - /* The max key in each bucket. */ - uintptr_t max[UPB_MAXARRSIZE + 1] = {0}; + if (!upb_Message_Next(msg, m, NULL, &f, &val, &iter)) { + jsonenc_err(e, "No value set in Value proto"); + } - upb_inttable_iter i; - size_t arr_count; - int size_lg2; - upb_inttable new_t; + switch (upb_FieldDef_Number(f)) { + case 1: + jsonenc_putstr(e, "null"); + break; + case 2: + upb_JsonEncode_Double(e, val.double_val); + break; + case 3: + jsonenc_string(e, val.str_val); + break; + case 4: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case 5: + jsonenc_struct(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + case 6: + jsonenc_listvalue(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + } +} - upb_inttable_begin(&i, t); - for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { - uintptr_t key = upb_inttable_iter_key(&i); - int bucket = log2ceil(key); - max[bucket] = UPB_MAX(max[bucket], key); - counts[bucket]++; +static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + switch (upb_MessageDef_WellKnownType(m)) { + case kUpb_WellKnown_Unspecified: + jsonenc_msg(e, msg, m); + break; + case kUpb_WellKnown_Any: + jsonenc_any(e, msg, m); + break; + case kUpb_WellKnown_FieldMask: + jsonenc_fieldmask(e, msg, m); + break; + case kUpb_WellKnown_Duration: + jsonenc_duration(e, msg, m); + break; + case kUpb_WellKnown_Timestamp: + jsonenc_timestamp(e, msg, m); + break; + case kUpb_WellKnown_DoubleValue: + case kUpb_WellKnown_FloatValue: + case kUpb_WellKnown_Int64Value: + case kUpb_WellKnown_UInt64Value: + case kUpb_WellKnown_Int32Value: + case kUpb_WellKnown_UInt32Value: + case kUpb_WellKnown_StringValue: + case kUpb_WellKnown_BytesValue: + case kUpb_WellKnown_BoolValue: + jsonenc_wrapper(e, msg, m); + break; + case kUpb_WellKnown_Value: + jsonenc_value(e, msg, m); + break; + case kUpb_WellKnown_ListValue: + jsonenc_listvalue(e, msg, m); + break; + case kUpb_WellKnown_Struct: + jsonenc_struct(e, msg, m); + break; } +} - /* Find the largest power of two that satisfies the MIN_DENSITY - * definition (while actually having some keys). */ - arr_count = upb_inttable_count(t); +static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case kUpb_CType_Float: + upb_JsonEncode_Float(e, val.float_val); + break; + case kUpb_CType_Double: + upb_JsonEncode_Double(e, val.double_val); + break; + case kUpb_CType_Int32: + jsonenc_printf(e, "%" PRId32, val.int32_val); + break; + case kUpb_CType_UInt32: + jsonenc_printf(e, "%" PRIu32, val.uint32_val); + break; + case kUpb_CType_Int64: + jsonenc_printf(e, "\"%" PRId64 "\"", val.int64_val); + break; + case kUpb_CType_UInt64: + jsonenc_printf(e, "\"%" PRIu64 "\"", val.uint64_val); + break; + case kUpb_CType_String: + jsonenc_string(e, val.str_val); + break; + case kUpb_CType_Bytes: + jsonenc_bytes(e, val.str_val); + break; + case kUpb_CType_Enum: + jsonenc_enum(val.int32_val, f, e); + break; + case kUpb_CType_Message: + jsonenc_msgfield(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + } +} - for (size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 0; size_lg2--) { - if (counts[size_lg2] == 0) { - /* We can halve again without losing any entries. */ - continue; - } else if (arr_count >= (1 << size_lg2) * MIN_DENSITY) { +static void jsonenc_mapkey(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f) { + jsonenc_putstr(e, "\""); + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case kUpb_CType_Int32: + jsonenc_printf(e, "%" PRId32, val.int32_val); + break; + case kUpb_CType_UInt32: + jsonenc_printf(e, "%" PRIu32, val.uint32_val); + break; + case kUpb_CType_Int64: + jsonenc_printf(e, "%" PRId64, val.int64_val); + break; + case kUpb_CType_UInt64: + jsonenc_printf(e, "%" PRIu64, val.uint64_val); + break; + case kUpb_CType_String: + jsonenc_stringbody(e, val.str_val); break; - } - - arr_count -= counts[size_lg2]; + default: + UPB_UNREACHABLE(); } - UPB_ASSERT(arr_count <= upb_inttable_count(t)); + jsonenc_putstr(e, "\":"); +} - { - /* Insert all elements into new, perfectly-sized table. */ - size_t arr_size = max[size_lg2] + 1; /* +1 so arr[max] will fit. */ - size_t hash_count = upb_inttable_count(t) - arr_count; - size_t hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0; - int hashsize_lg2 = log2ceil(hash_size); +static void jsonenc_array(jsonenc* e, const upb_Array* arr, + const upb_FieldDef* f) { + size_t i; + size_t size = arr ? upb_Array_Size(arr) : 0; + bool first = true; - upb_inttable_sizedinit(&new_t, arr_size, hashsize_lg2, a); - upb_inttable_begin(&i, t); - for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { - uintptr_t k = upb_inttable_iter_key(&i); - upb_inttable_insert(&new_t, k, upb_inttable_iter_value(&i), a); - } - UPB_ASSERT(new_t.array_size == arr_size); - UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2); - } - *t = new_t; -} + jsonenc_putstr(e, "["); -/* Iteration. */ + for (i = 0; i < size; i++) { + jsonenc_putsep(e, ",", &first); + jsonenc_scalar(e, upb_Array_Get(arr, i), f); + } -static const upb_tabent* int_tabent(const upb_inttable_iter* i) { - UPB_ASSERT(!i->array_part); - return &i->t->t.entries[i->index]; + jsonenc_putstr(e, "]"); } -static upb_tabval int_arrent(const upb_inttable_iter* i) { - UPB_ASSERT(i->array_part); - return i->t->array[i->index]; -} +static void jsonenc_map(jsonenc* e, const upb_Map* map, const upb_FieldDef* f) { + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); + size_t iter = kUpb_Map_Begin; + bool first = true; -void upb_inttable_begin(upb_inttable_iter* i, const upb_inttable* t) { - i->t = t; - i->index = -1; - i->array_part = true; - upb_inttable_next(i); -} + jsonenc_putstr(e, "{"); -void upb_inttable_next(upb_inttable_iter* iter) { - const upb_inttable* t = iter->t; - if (iter->array_part) { - while (++iter->index < t->array_size) { - if (upb_arrhas(int_arrent(iter))) { - return; - } + if (map) { + while (upb_MapIterator_Next(map, &iter)) { + jsonenc_putsep(e, ",", &first); + jsonenc_mapkey(e, upb_MapIterator_Key(map, iter), key_f); + jsonenc_scalar(e, upb_MapIterator_Value(map, iter), val_f); } - iter->array_part = false; - iter->index = begin(&t->t); - } else { - iter->index = next(&t->t, iter->index); } + + jsonenc_putstr(e, "}"); } -bool upb_inttable_next2(const upb_inttable* t, uintptr_t* key, upb_value* val, - intptr_t* iter) { - intptr_t i = *iter; - if (i < t->array_size) { - while (++i < t->array_size) { - upb_tabval ent = t->array[i]; - if (upb_arrhas(ent)) { - *key = i; - *val = _upb_value_val(ent.val); - *iter = i; - return true; - } +static void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f, + upb_MessageValue val, bool* first) { + const char* name; + + jsonenc_putsep(e, ",", first); + + if (upb_FieldDef_IsExtension(f)) { + // TODO: For MessageSet, I would have expected this to print the message + // name here, but Python doesn't appear to do this. We should do more + // research here about what various implementations do. + jsonenc_printf(e, "\"[%s]\":", upb_FieldDef_FullName(f)); + } else { + if (e->options & upb_JsonEncode_UseProtoNames) { + name = upb_FieldDef_Name(f); + } else { + name = upb_FieldDef_JsonName(f); } + jsonenc_printf(e, "\"%s\":", name); } - size_t tab_idx = next(&t->t, i == -1 ? -1 : i - t->array_size); - if (tab_idx < upb_table_size(&t->t)) { - upb_tabent* ent = &t->t.entries[tab_idx]; - *key = ent->key; - *val = _upb_value_val(ent->val.val); - *iter = tab_idx + t->array_size; - return true; + if (upb_FieldDef_IsMap(f)) { + jsonenc_map(e, val.map_val, f); + } else if (upb_FieldDef_IsRepeated(f)) { + jsonenc_array(e, val.array_val, f); + } else { + jsonenc_scalar(e, val, f); } - - return false; } -void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter) { - intptr_t i = *iter; - if (i < t->array_size) { - t->array_count--; - mutable_array(t)[i].val = -1; - } else { - upb_tabent* ent = &t->t.entries[i - t->array_size]; - upb_tabent* prev = NULL; +static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m, bool first) { + upb_MessageValue val; + const upb_FieldDef* f; - // Linear search, not great. - upb_tabent* end = &t->t.entries[upb_table_size(&t->t)]; - for (upb_tabent* e = t->t.entries; e != end; e++) { - if (e->next == ent) { - prev = e; - break; + if (e->options & upb_JsonEncode_EmitDefaults) { + /* Iterate over all fields. */ + int i = 0; + int n = upb_MessageDef_FieldCount(m); + for (i = 0; i < n; i++) { + f = upb_MessageDef_Field(m, i); + if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) { + jsonenc_fieldval(e, f, upb_Message_Get(msg, f), &first); } } - - if (prev) { - prev->next = ent->next; + } else { + /* Iterate over non-empty fields. */ + size_t iter = kUpb_Message_Begin; + while (upb_Message_Next(msg, m, e->ext_pool, &f, &val, &iter)) { + jsonenc_fieldval(e, f, val, &first); } - - t->t.count--; - ent->key = 0; - ent->next = NULL; } } -bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key, - upb_value* val, intptr_t* iter) { - size_t tab_idx = next(&t->t, *iter); - if (tab_idx < upb_table_size(&t->t)) { - upb_tabent* ent = &t->t.entries[tab_idx]; - uint32_t len; - key->data = upb_tabstr(ent->key, &len); - key->size = len; - *val = _upb_value_val(ent->val.val); - *iter = tab_idx; - return true; - } - - return false; +static void jsonenc_msg(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + jsonenc_putstr(e, "{"); + jsonenc_msgfields(e, msg, m, true); + jsonenc_putstr(e, "}"); } -void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter) { - intptr_t i = *iter; - upb_tabent* ent = &t->t.entries[i]; - upb_tabent* prev = NULL; - - // Linear search, not great. - upb_tabent* end = &t->t.entries[upb_table_size(&t->t)]; - for (upb_tabent* e = t->t.entries; e != end; e++) { - if (e->next == ent) { - prev = e; - break; - } - } +static size_t jsonenc_nullz(jsonenc* e, size_t size) { + size_t ret = e->ptr - e->buf + e->overflow; - if (prev) { - prev->next = ent->next; + if (size > 0) { + if (e->ptr == e->end) e->ptr--; + *e->ptr = '\0'; } - t->t.count--; - ent->key = 0; - ent->next = NULL; -} - -bool upb_inttable_done(const upb_inttable_iter* i) { - if (!i->t) return true; - if (i->array_part) { - return i->index >= i->t->array_size || !upb_arrhas(int_arrent(i)); - } else { - return i->index >= upb_table_size(&i->t->t) || - upb_tabent_isempty(int_tabent(i)); - } + return ret; } -uintptr_t upb_inttable_iter_key(const upb_inttable_iter* i) { - UPB_ASSERT(!upb_inttable_done(i)); - return i->array_part ? i->index : int_tabent(i)->key; -} +size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, int options, char* buf, + size_t size, upb_Status* status) { + jsonenc e; -upb_value upb_inttable_iter_value(const upb_inttable_iter* i) { - UPB_ASSERT(!upb_inttable_done(i)); - return _upb_value_val(i->array_part ? i->t->array[i->index].val - : int_tabent(i)->val.val); -} + e.buf = buf; + e.ptr = buf; + e.end = UPB_PTRADD(buf, size); + e.overflow = 0; + e.options = options; + e.ext_pool = ext_pool; + e.status = status; + e.arena = NULL; -void upb_inttable_iter_setdone(upb_inttable_iter* i) { - i->t = NULL; - i->index = SIZE_MAX; - i->array_part = false; -} + if (setjmp(e.err)) return -1; -bool upb_inttable_iter_isequal(const upb_inttable_iter* i1, - const upb_inttable_iter* i2) { - if (upb_inttable_done(i1) && upb_inttable_done(i2)) return true; - return i1->t == i2->t && i1->index == i2->index && - i1->array_part == i2->array_part; + jsonenc_msgfield(&e, msg, m); + if (e.arena) upb_Arena_Free(e.arena); + return jsonenc_nullz(&e, size); } -/** upb/upb.c ************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include - + +#include +#include + // Must be last. -/* upb_Status *****************************************************************/ +typedef enum { + kUpb_EncodedType_Double = 0, + kUpb_EncodedType_Float = 1, + kUpb_EncodedType_Fixed32 = 2, + kUpb_EncodedType_Fixed64 = 3, + kUpb_EncodedType_SFixed32 = 4, + kUpb_EncodedType_SFixed64 = 5, + kUpb_EncodedType_Int32 = 6, + kUpb_EncodedType_UInt32 = 7, + kUpb_EncodedType_SInt32 = 8, + kUpb_EncodedType_Int64 = 9, + kUpb_EncodedType_UInt64 = 10, + kUpb_EncodedType_SInt64 = 11, + kUpb_EncodedType_Enum = 12, + kUpb_EncodedType_Bool = 13, + kUpb_EncodedType_Bytes = 14, + kUpb_EncodedType_String = 15, + kUpb_EncodedType_Group = 16, + kUpb_EncodedType_Message = 17, + + kUpb_EncodedType_RepeatedBase = 20, +} upb_EncodedType; -void upb_Status_Clear(upb_Status* status) { - if (!status) return; - status->ok = true; - status->msg[0] = '\0'; -} +typedef enum { + kUpb_EncodedFieldModifier_FlipPacked = 1 << 0, + kUpb_EncodedFieldModifier_IsClosedEnum = 1 << 1, + // upb only. + kUpb_EncodedFieldModifier_IsProto3Singular = 1 << 2, + kUpb_EncodedFieldModifier_IsRequired = 1 << 3, +} upb_EncodedFieldModifier; + +enum { + kUpb_EncodedValue_MinField = ' ', + kUpb_EncodedValue_MaxField = 'K', + kUpb_EncodedValue_MinModifier = 'L', + kUpb_EncodedValue_MaxModifier = '[', + kUpb_EncodedValue_End = '^', + kUpb_EncodedValue_MinSkip = '_', + kUpb_EncodedValue_MaxSkip = '~', + kUpb_EncodedValue_OneofSeparator = '~', + kUpb_EncodedValue_FieldSeparator = '|', + kUpb_EncodedValue_MinOneofField = ' ', + kUpb_EncodedValue_MaxOneofField = 'b', + kUpb_EncodedValue_MaxEnumMask = 'A', +}; -bool upb_Status_IsOk(const upb_Status* status) { return status->ok; } +char upb_ToBase92(int8_t ch) { + static const char kUpb_ToBase92[] = { + ' ', '!', '#', '$', '%', '&', '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', + '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', + 'Z', '[', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '{', '|', '}', '~', + }; -const char* upb_Status_ErrorMessage(const upb_Status* status) { - return status->msg; + UPB_ASSERT(0 <= ch && ch < 92); + return kUpb_ToBase92[ch]; } -void upb_Status_SetErrorMessage(upb_Status* status, const char* msg) { - if (!status) return; - status->ok = false; - strncpy(status->msg, msg, _kUpb_Status_MaxMessage - 1); - status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; -} +char upb_FromBase92(uint8_t ch) { + static const int8_t kUpb_FromBase92[] = { + 0, 1, -1, 2, 3, 4, 5, -1, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + }; -void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) { - va_list args; - va_start(args, fmt); - upb_Status_VSetErrorFormat(status, fmt, args); - va_end(args); + if (' ' > ch || ch > '~') return -1; + return kUpb_FromBase92[ch - ' ']; } -void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, - va_list args) { - if (!status) return; - status->ok = false; - vsnprintf(status->msg, sizeof(status->msg), fmt, args); - status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; +bool upb_IsTypePackable(upb_FieldType type) { + // clang-format off + static const unsigned kUnpackableTypes = + (1 << kUpb_FieldType_String) | + (1 << kUpb_FieldType_Bytes) | + (1 << kUpb_FieldType_Message) | + (1 << kUpb_FieldType_Group); + // clang-format on + return (1 << type) & ~kUnpackableTypes; } -void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, - va_list args) { - size_t len; - if (!status) return; - status->ok = false; - len = strlen(status->msg); - vsnprintf(status->msg + len, sizeof(status->msg) - len, fmt, args); - status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; -} +/** upb_MtDataEncoder *********************************************************/ -/* upb_alloc ******************************************************************/ +typedef struct { + uint64_t present_values_mask; + uint32_t last_written_value; +} upb_MtDataEncoderInternal_EnumState; -static void* upb_global_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize, - size_t size) { - UPB_UNUSED(alloc); - UPB_UNUSED(oldsize); - if (size == 0) { - free(ptr); - return NULL; - } else { - return realloc(ptr, size); - } -} +typedef struct { + uint64_t msg_modifiers; + uint32_t last_field_num; + enum { + kUpb_OneofState_NotStarted, + kUpb_OneofState_StartedOneof, + kUpb_OneofState_EmittedOneofField, + } oneof_state; +} upb_MtDataEncoderInternal_MsgState; -static uint32_t* upb_cleanup_pointer(uintptr_t cleanup_metadata) { - return (uint32_t*)(cleanup_metadata & ~0x1); +typedef struct { + char* buf_start; // Only for checking kUpb_MtDataEncoder_MinSize. + union { + upb_MtDataEncoderInternal_EnumState enum_state; + upb_MtDataEncoderInternal_MsgState msg_state; + } state; +} upb_MtDataEncoderInternal; + +static upb_MtDataEncoderInternal* upb_MtDataEncoder_GetInternal( + upb_MtDataEncoder* e, char* buf_start) { + UPB_ASSERT(sizeof(upb_MtDataEncoderInternal) <= sizeof(e->internal)); + upb_MtDataEncoderInternal* ret = (upb_MtDataEncoderInternal*)e->internal; + ret->buf_start = buf_start; + return ret; } -static bool upb_cleanup_has_initial_block(uintptr_t cleanup_metadata) { - return cleanup_metadata & 0x1; +static char* upb_MtDataEncoder_Put(upb_MtDataEncoder* e, char* ptr, char ch) { + upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; + UPB_ASSERT(ptr - in->buf_start < kUpb_MtDataEncoder_MinSize); + if (ptr == e->end) return NULL; + *ptr++ = upb_ToBase92(ch); + return ptr; } -static uintptr_t upb_cleanup_metadata(uint32_t* cleanup, - bool has_initial_block) { - return (uintptr_t)cleanup | has_initial_block; +static char* upb_MtDataEncoder_PutBase92Varint(upb_MtDataEncoder* e, char* ptr, + uint32_t val, int min, int max) { + int shift = _upb_Log2Ceiling(upb_FromBase92(max) - upb_FromBase92(min) + 1); + UPB_ASSERT(shift <= 6); + uint32_t mask = (1 << shift) - 1; + do { + uint32_t bits = val & mask; + ptr = upb_MtDataEncoder_Put(e, ptr, bits + upb_FromBase92(min)); + if (!ptr) return NULL; + val >>= shift; + } while (val); + return ptr; } -upb_alloc upb_alloc_global = {&upb_global_allocfunc}; - -/* upb_Arena ******************************************************************/ - -/* Be conservative and choose 16 in case anyone is using SSE. */ - -struct mem_block { - struct mem_block* next; - uint32_t size; - uint32_t cleanups; - /* Data follows. */ -}; - -typedef struct cleanup_ent { - upb_CleanupFunc* cleanup; - void* ud; -} cleanup_ent; - -static const size_t memblock_reserve = UPB_ALIGN_UP(sizeof(mem_block), 16); - -static upb_Arena* arena_findroot(upb_Arena* a) { - /* Path splitting keeps time complexity down, see: - * https://en.wikipedia.org/wiki/Disjoint-set_data_structure */ - while (a->parent != a) { - upb_Arena* next = a->parent; - a->parent = next->parent; - a = next; +char* upb_MtDataEncoder_PutModifier(upb_MtDataEncoder* e, char* ptr, + uint64_t mod) { + if (mod) { + ptr = upb_MtDataEncoder_PutBase92Varint(e, ptr, mod, + kUpb_EncodedValue_MinModifier, + kUpb_EncodedValue_MaxModifier); } - return a; + return ptr; } -static void upb_Arena_addblock(upb_Arena* a, upb_Arena* root, void* ptr, - size_t size) { - mem_block* block = ptr; - - /* The block is for arena |a|, but should appear in the freelist of |root|. */ - block->next = root->freelist; - block->size = (uint32_t)size; - block->cleanups = 0; - root->freelist = block; - a->last_size = block->size; - if (!root->freelist_tail) root->freelist_tail = block; +char* upb_MtDataEncoder_StartMessage(upb_MtDataEncoder* e, char* ptr, + uint64_t msg_mod) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + in->state.msg_state.msg_modifiers = msg_mod; + in->state.msg_state.last_field_num = 0; + in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; + return upb_MtDataEncoder_PutModifier(e, ptr, msg_mod); +} + +char* upb_MtDataEncoder_PutField(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod) { + static const char kUpb_TypeToEncoded[] = { + [kUpb_FieldType_Double] = kUpb_EncodedType_Double, + [kUpb_FieldType_Float] = kUpb_EncodedType_Float, + [kUpb_FieldType_Int64] = kUpb_EncodedType_Int64, + [kUpb_FieldType_UInt64] = kUpb_EncodedType_UInt64, + [kUpb_FieldType_Int32] = kUpb_EncodedType_Int32, + [kUpb_FieldType_Fixed64] = kUpb_EncodedType_Fixed64, + [kUpb_FieldType_Fixed32] = kUpb_EncodedType_Fixed32, + [kUpb_FieldType_Bool] = kUpb_EncodedType_Bool, + [kUpb_FieldType_String] = kUpb_EncodedType_String, + [kUpb_FieldType_Group] = kUpb_EncodedType_Group, + [kUpb_FieldType_Message] = kUpb_EncodedType_Message, + [kUpb_FieldType_Bytes] = kUpb_EncodedType_Bytes, + [kUpb_FieldType_UInt32] = kUpb_EncodedType_UInt32, + [kUpb_FieldType_Enum] = kUpb_EncodedType_Enum, + [kUpb_FieldType_SFixed32] = kUpb_EncodedType_SFixed32, + [kUpb_FieldType_SFixed64] = kUpb_EncodedType_SFixed64, + [kUpb_FieldType_SInt32] = kUpb_EncodedType_SInt32, + [kUpb_FieldType_SInt64] = kUpb_EncodedType_SInt64, + }; - a->head.ptr = UPB_PTR_AT(block, memblock_reserve, char); - a->head.end = UPB_PTR_AT(block, size, char); - a->cleanup_metadata = upb_cleanup_metadata( - &block->cleanups, upb_cleanup_has_initial_block(a->cleanup_metadata)); + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (field_num <= in->state.msg_state.last_field_num) return NULL; + if (in->state.msg_state.last_field_num + 1 != field_num) { + // Put skip. + UPB_ASSERT(field_num > in->state.msg_state.last_field_num); + uint32_t skip = field_num - in->state.msg_state.last_field_num; + ptr = upb_MtDataEncoder_PutBase92Varint( + e, ptr, skip, kUpb_EncodedValue_MinSkip, kUpb_EncodedValue_MaxSkip); + if (!ptr) return NULL; + } + in->state.msg_state.last_field_num = field_num; + + uint32_t encoded_modifiers = 0; + + // Put field type. + if (type == kUpb_FieldType_Enum && + !(field_mod & kUpb_FieldModifier_IsClosedEnum)) { + type = kUpb_FieldType_Int32; + } + + int encoded_type = kUpb_TypeToEncoded[type]; + if (field_mod & kUpb_FieldModifier_IsRepeated) { + // Repeated fields shift the type number up (unlike other modifiers which + // are bit flags). + encoded_type += kUpb_EncodedType_RepeatedBase; + + if (upb_IsTypePackable(type)) { + bool field_is_packed = field_mod & kUpb_FieldModifier_IsPacked; + bool default_is_packed = in->state.msg_state.msg_modifiers & + kUpb_MessageModifier_DefaultIsPacked; + if (field_is_packed != default_is_packed) { + encoded_modifiers |= kUpb_EncodedFieldModifier_FlipPacked; + } + } + } + ptr = upb_MtDataEncoder_Put(e, ptr, encoded_type); + if (!ptr) return NULL; - UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr); + if (field_mod & kUpb_FieldModifier_IsProto3Singular) { + encoded_modifiers |= kUpb_EncodedFieldModifier_IsProto3Singular; + } + if (field_mod & kUpb_FieldModifier_IsRequired) { + encoded_modifiers |= kUpb_EncodedFieldModifier_IsRequired; + } + return upb_MtDataEncoder_PutModifier(e, ptr, encoded_modifiers); } -static bool upb_Arena_Allocblock(upb_Arena* a, size_t size) { - upb_Arena* root = arena_findroot(a); - size_t block_size = UPB_MAX(size, a->last_size * 2) + memblock_reserve; - mem_block* block = upb_malloc(root->block_alloc, block_size); - - if (!block) return false; - upb_Arena_addblock(a, root, block, block_size); - return true; +char* upb_MtDataEncoder_StartOneof(upb_MtDataEncoder* e, char* ptr) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (in->state.msg_state.oneof_state == kUpb_OneofState_NotStarted) { + ptr = upb_MtDataEncoder_Put(e, ptr, upb_FromBase92(kUpb_EncodedValue_End)); + } else { + ptr = upb_MtDataEncoder_Put( + e, ptr, upb_FromBase92(kUpb_EncodedValue_OneofSeparator)); + } + in->state.msg_state.oneof_state = kUpb_OneofState_StartedOneof; + return ptr; } -void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size) { - if (!upb_Arena_Allocblock(a, size)) return NULL; /* Out of memory. */ - UPB_ASSERT(_upb_ArenaHas(a) >= size); - return upb_Arena_Malloc(a, size); +char* upb_MtDataEncoder_PutOneofField(upb_MtDataEncoder* e, char* ptr, + uint32_t field_num) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (in->state.msg_state.oneof_state == kUpb_OneofState_EmittedOneofField) { + ptr = upb_MtDataEncoder_Put( + e, ptr, upb_FromBase92(kUpb_EncodedValue_FieldSeparator)); + if (!ptr) return NULL; + } + ptr = upb_MtDataEncoder_PutBase92Varint(e, ptr, field_num, upb_ToBase92(0), + upb_ToBase92(63)); + in->state.msg_state.oneof_state = kUpb_OneofState_EmittedOneofField; + return ptr; } -static void* upb_Arena_doalloc(upb_alloc* alloc, void* ptr, size_t oldsize, - size_t size) { - upb_Arena* a = (upb_Arena*)alloc; /* upb_alloc is initial member. */ - return upb_Arena_Realloc(a, ptr, oldsize, size); +void upb_MtDataEncoder_StartEnum(upb_MtDataEncoder* e) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, NULL); + in->state.enum_state.present_values_mask = 0; + in->state.enum_state.last_written_value = 0; } -/* Public Arena API ***********************************************************/ - -upb_Arena* arena_initslow(void* mem, size_t n, upb_alloc* alloc) { - const size_t first_block_overhead = sizeof(upb_Arena) + memblock_reserve; - upb_Arena* a; +static char* upb_MtDataEncoder_FlushDenseEnumMask(upb_MtDataEncoder* e, + char* ptr) { + upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; + ptr = upb_MtDataEncoder_Put(e, ptr, in->state.enum_state.present_values_mask); + in->state.enum_state.present_values_mask = 0; + in->state.enum_state.last_written_value += 5; + return ptr; +} - /* We need to malloc the initial block. */ - n = first_block_overhead + 256; - if (!alloc || !(mem = upb_malloc(alloc, n))) { - return NULL; +char* upb_MtDataEncoder_PutEnumValue(upb_MtDataEncoder* e, char* ptr, + uint32_t val) { + // TODO(b/229641772): optimize this encoding. + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + UPB_ASSERT(val >= in->state.enum_state.last_written_value); + uint32_t delta = val - in->state.enum_state.last_written_value; + if (delta >= 5 && in->state.enum_state.present_values_mask) { + ptr = upb_MtDataEncoder_FlushDenseEnumMask(e, ptr); + if (!ptr) { + return NULL; + } + delta -= 5; } - a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); - n -= sizeof(*a); - - a->head.alloc.func = &upb_Arena_doalloc; - a->block_alloc = alloc; - a->parent = a; - a->refcount = 1; - a->freelist = NULL; - a->freelist_tail = NULL; - a->cleanup_metadata = upb_cleanup_metadata(NULL, false); - - upb_Arena_addblock(a, a, mem, n); + if (delta >= 5) { + ptr = upb_MtDataEncoder_PutBase92Varint( + e, ptr, delta, kUpb_EncodedValue_MinSkip, kUpb_EncodedValue_MaxSkip); + in->state.enum_state.last_written_value += delta; + delta = 0; + } - return a; + UPB_ASSERT((in->state.enum_state.present_values_mask >> delta) == 0); + in->state.enum_state.present_values_mask |= 1ULL << delta; + return ptr; } -upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) { - upb_Arena* a; +char* upb_MtDataEncoder_EndEnum(upb_MtDataEncoder* e, char* ptr) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (!in->state.enum_state.present_values_mask) return ptr; + return upb_MtDataEncoder_FlushDenseEnumMask(e, ptr); +} - if (n) { - /* Align initial pointer up so that we return properly-aligned pointers. */ - void* aligned = (void*)UPB_ALIGN_UP((uintptr_t)mem, 16); - size_t delta = (uintptr_t)aligned - (uintptr_t)mem; - n = delta <= n ? n - delta : 0; - mem = aligned; +const upb_MiniTable_Field* upb_MiniTable_FindFieldByNumber( + const upb_MiniTable* table, uint32_t number) { + int n = table->field_count; + for (int i = 0; i < n; i++) { + if (table->fields[i].number == number) { + return &table->fields[i]; + } } + return NULL; +} - /* Round block size down to alignof(*a) since we will allocate the arena - * itself at the end. */ - n = UPB_ALIGN_DOWN(n, UPB_ALIGN_OF(upb_Arena)); +/** Data decoder **************************************************************/ - if (UPB_UNLIKELY(n < sizeof(upb_Arena))) { - return arena_initslow(mem, n, alloc); - } +// Note: we sort by this number when calculating layout order. +typedef enum { + kUpb_LayoutItemType_OneofCase, // Oneof case. + kUpb_LayoutItemType_OneofField, // Oneof field data. + kUpb_LayoutItemType_Field, // Non-oneof field data. - a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); + kUpb_LayoutItemType_Max = kUpb_LayoutItemType_Field, +} upb_LayoutItemType; - a->head.alloc.func = &upb_Arena_doalloc; - a->block_alloc = alloc; - a->parent = a; - a->refcount = 1; - a->last_size = UPB_MAX(128, n); - a->head.ptr = mem; - a->head.end = UPB_PTR_AT(mem, n - sizeof(*a), char); - a->freelist = NULL; - a->cleanup_metadata = upb_cleanup_metadata(NULL, true); +#define kUpb_LayoutItem_IndexSentinel ((uint16_t)-1) - return a; -} +typedef struct { + // Index of the corresponding field. When this is a oneof field, the field's + // offset will be the index of the next field in a linked list. + uint16_t field_index; + uint16_t offset; + upb_FieldRep rep; + upb_LayoutItemType type; +} upb_LayoutItem; -static void arena_dofree(upb_Arena* a) { - mem_block* block = a->freelist; - UPB_ASSERT(a->parent == a); - UPB_ASSERT(a->refcount == 0); +typedef struct { + upb_LayoutItem* data; + size_t size; + size_t capacity; +} upb_LayoutItemVector; - while (block) { - /* Load first since we are deleting block. */ - mem_block* next = block->next; +typedef struct { + const char* end; + upb_MiniTable* table; + upb_MiniTable_Field* fields; + upb_MiniTablePlatform platform; + upb_LayoutItemVector vec; + upb_Arena* arena; + upb_Status* status; - if (block->cleanups > 0) { - cleanup_ent* end = UPB_PTR_AT(block, block->size, void); - cleanup_ent* ptr = end - block->cleanups; + // When building enums. + upb_MiniTable_Enum* enum_table; + uint32_t enum_value_count; + uint32_t enum_data_count; + uint32_t enum_data_capacity; - for (; ptr < end; ptr++) { - ptr->cleanup(ptr->ud); - } - } + jmp_buf err; +} upb_MtDecoder; - upb_free(a->block_alloc, block); - block = next; - } +UPB_PRINTF(2, 3) +UPB_NORETURN static void upb_MtDecoder_ErrorFormat(upb_MtDecoder* d, + const char* fmt, ...) { + va_list argp; + upb_Status_SetErrorMessage(d->status, "Error building mini table: "); + va_start(argp, fmt); + upb_Status_VAppendErrorFormat(d->status, fmt, argp); + va_end(argp); + UPB_LONGJMP(d->err, 1); } -void upb_Arena_Free(upb_Arena* a) { - a = arena_findroot(a); - if (--a->refcount == 0) arena_dofree(a); +static void upb_MtDecoder_CheckOutOfMemory(upb_MtDecoder* d, const void* ptr) { + if (!ptr) upb_MtDecoder_ErrorFormat(d, "Out of memory"); } -bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func) { - cleanup_ent* ent; - uint32_t* cleanups = upb_cleanup_pointer(a->cleanup_metadata); +// In each field's offset, we temporarily store a presence classifier: +enum PresenceClass { + kNoPresence = 0, + kHasbitPresence = 1, + kRequiredPresence = 2, + kOneofBase = 3, + // Negative values refer to a specific oneof with that number. Positive + // values >= kOneofBase indicate that this field is in a oneof, and specify + // the next field in this oneof's linked list. +}; - if (!cleanups || _upb_ArenaHas(a) < sizeof(cleanup_ent)) { - if (!upb_Arena_Allocblock(a, 128)) return false; /* Out of memory. */ - UPB_ASSERT(_upb_ArenaHas(a) >= sizeof(cleanup_ent)); - cleanups = upb_cleanup_pointer(a->cleanup_metadata); +static const char* upb_MiniTable_DecodeBase92Varint(upb_MtDecoder* d, + const char* ptr, + char first_ch, uint8_t min, + uint8_t max, + uint32_t* out_val) { + uint32_t val = 0; + uint32_t shift = 0; + const int bits_per_char = + _upb_Log2Ceiling(upb_FromBase92(max) - upb_FromBase92(min)); + char ch = first_ch; + while (1) { + uint32_t bits = upb_FromBase92(ch) - upb_FromBase92(min); + val |= bits << shift; + if (ptr == d->end || *ptr < min || max < *ptr) { + *out_val = val; + return ptr; + } + ch = *ptr++; + shift += bits_per_char; + if (shift >= 32) upb_MtDecoder_ErrorFormat(d, "Overlong varint"); } +} - a->head.end -= sizeof(cleanup_ent); - ent = (cleanup_ent*)a->head.end; - (*cleanups)++; - UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent)); - - ent->cleanup = func; - ent->ud = ud; - - return true; +static bool upb_MiniTable_HasSub(upb_MiniTable_Field* field, + uint64_t msg_modifiers) { + switch (field->descriptortype) { + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + case kUpb_FieldType_Enum: + return true; + case kUpb_FieldType_String: + if (!(msg_modifiers & kUpb_MessageModifier_ValidateUtf8)) { + field->descriptortype = kUpb_FieldType_Bytes; + } + return false; + default: + return false; + } } -bool upb_Arena_Fuse(upb_Arena* a1, upb_Arena* a2) { - upb_Arena* r1 = arena_findroot(a1); - upb_Arena* r2 = arena_findroot(a2); - - if (r1 == r2) return true; /* Already fused. */ +static bool upb_MtDecoder_FieldIsPackable(upb_MiniTable_Field* field) { + return (field->mode & kUpb_FieldMode_Array) && + upb_IsTypePackable(field->descriptortype); +} - /* Do not fuse initial blocks since we cannot lifetime extend them. */ - if (upb_cleanup_has_initial_block(r1->cleanup_metadata)) return false; - if (upb_cleanup_has_initial_block(r2->cleanup_metadata)) return false; +static void upb_MiniTable_SetTypeAndSub(upb_MiniTable_Field* field, + upb_FieldType type, uint32_t* sub_count, + uint64_t msg_modifiers) { + field->descriptortype = type; + if (upb_MiniTable_HasSub(field, msg_modifiers)) { + field->submsg_index = sub_count ? (*sub_count)++ : 0; + } else { + field->submsg_index = kUpb_NoSub; + } + + if (upb_MtDecoder_FieldIsPackable(field) && + (msg_modifiers & kUpb_MessageModifier_DefaultIsPacked)) { + field->mode |= kUpb_LabelFlags_IsPacked; + } +} + +static void upb_MiniTable_SetField(upb_MtDecoder* d, uint8_t ch, + upb_MiniTable_Field* field, + uint64_t msg_modifiers, + uint32_t* sub_count) { + static const char kUpb_EncodedToFieldRep[] = { + [kUpb_EncodedType_Double] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Float] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Int64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_UInt64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Int32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Fixed64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Fixed32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Bool] = kUpb_FieldRep_1Byte, + [kUpb_EncodedType_String] = kUpb_FieldRep_StringView, + [kUpb_EncodedType_Group] = kUpb_FieldRep_Pointer, + [kUpb_EncodedType_Message] = kUpb_FieldRep_Pointer, + [kUpb_EncodedType_Bytes] = kUpb_FieldRep_StringView, + [kUpb_EncodedType_UInt32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Enum] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SFixed32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SFixed64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_SInt32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SInt64] = kUpb_FieldRep_8Byte, + }; - /* Only allow fuse with a common allocator */ - if (r1->block_alloc != r2->block_alloc) return false; + static const char kUpb_EncodedToType[] = { + [kUpb_EncodedType_Double] = kUpb_FieldType_Double, + [kUpb_EncodedType_Float] = kUpb_FieldType_Float, + [kUpb_EncodedType_Int64] = kUpb_FieldType_Int64, + [kUpb_EncodedType_UInt64] = kUpb_FieldType_UInt64, + [kUpb_EncodedType_Int32] = kUpb_FieldType_Int32, + [kUpb_EncodedType_Fixed64] = kUpb_FieldType_Fixed64, + [kUpb_EncodedType_Fixed32] = kUpb_FieldType_Fixed32, + [kUpb_EncodedType_Bool] = kUpb_FieldType_Bool, + [kUpb_EncodedType_String] = kUpb_FieldType_String, + [kUpb_EncodedType_Group] = kUpb_FieldType_Group, + [kUpb_EncodedType_Message] = kUpb_FieldType_Message, + [kUpb_EncodedType_Bytes] = kUpb_FieldType_Bytes, + [kUpb_EncodedType_UInt32] = kUpb_FieldType_UInt32, + [kUpb_EncodedType_Enum] = kUpb_FieldType_Enum, + [kUpb_EncodedType_SFixed32] = kUpb_FieldType_SFixed32, + [kUpb_EncodedType_SFixed64] = kUpb_FieldType_SFixed64, + [kUpb_EncodedType_SInt32] = kUpb_FieldType_SInt32, + [kUpb_EncodedType_SInt64] = kUpb_FieldType_SInt64, + }; - /* We want to join the smaller tree to the larger tree. - * So swap first if they are backwards. */ - if (r1->refcount < r2->refcount) { - upb_Arena* tmp = r1; - r1 = r2; - r2 = tmp; + int8_t type = upb_FromBase92(ch); + if (ch >= upb_ToBase92(kUpb_EncodedType_RepeatedBase)) { + type -= kUpb_EncodedType_RepeatedBase; + field->mode = kUpb_FieldMode_Array; + field->mode |= kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift; + field->offset = kNoPresence; + } else { + if (type >= sizeof(kUpb_EncodedToFieldRep)) { + upb_MtDecoder_ErrorFormat(d, "Invalid field type: %d", (int)type); + UPB_UNREACHABLE(); + } + field->mode = kUpb_FieldMode_Scalar; + field->mode |= kUpb_EncodedToFieldRep[type] << kUpb_FieldRep_Shift; + field->offset = kHasbitPresence; } - - /* r1 takes over r2's freelist and refcount. */ - r1->refcount += r2->refcount; - if (r2->freelist_tail) { - UPB_ASSERT(r2->freelist_tail->next == NULL); - r2->freelist_tail->next = r1->freelist; - r1->freelist = r2->freelist; + if (type >= sizeof(kUpb_EncodedToType)) { + upb_MtDecoder_ErrorFormat(d, "Invalid field type: %d", (int)type); + UPB_UNREACHABLE(); } - r2->parent = r1; - return true; + upb_MiniTable_SetTypeAndSub(field, kUpb_EncodedToType[type], sub_count, + msg_modifiers); } -/* Miscellaneous utilities ****************************************************/ +static void upb_MtDecoder_ModifyField(upb_MtDecoder* d, + uint32_t message_modifiers, + uint32_t field_modifiers, + upb_MiniTable_Field* field) { + if (field_modifiers & kUpb_EncodedFieldModifier_FlipPacked) { + if (!upb_MtDecoder_FieldIsPackable(field)) { + upb_MtDecoder_ErrorFormat( + d, "Cannot flip packed on unpackable field %" PRIu32, field->number); + UPB_UNREACHABLE(); + } + field->mode ^= kUpb_LabelFlags_IsPacked; + } -static void upb_FixLocale(char* p) { - /* printf() is dependent on locales; sadly there is no easy and portable way - * to avoid this. This little post-processing step will translate 1,2 -> 1.2 - * since JSON needs the latter. Arguably a hack, but it is simple and the - * alternatives are far more complicated, platform-dependent, and/or larger - * in code size. */ - for (; *p; p++) { - if (*p == ',') *p = '.'; + bool singular = field_modifiers & kUpb_EncodedFieldModifier_IsProto3Singular; + bool required = field_modifiers & kUpb_EncodedFieldModifier_IsRequired; + + // Validate. + if ((singular || required) && field->offset != kHasbitPresence) { + upb_MtDecoder_ErrorFormat( + d, "Invalid modifier(s) for repeated field %" PRIu32, field->number); + UPB_UNREACHABLE(); + } + if (singular && required) { + upb_MtDecoder_ErrorFormat( + d, "Field %" PRIu32 " cannot be both singular and required", + field->number); + UPB_UNREACHABLE(); } -} -void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size) { - assert(size >= kUpb_RoundTripBufferSize); - snprintf(buf, size, "%.*g", DBL_DIG, val); - if (strtod(buf, NULL) != val) { - snprintf(buf, size, "%.*g", DBL_DIG + 2, val); - assert(strtod(buf, NULL) == val); + if (singular) field->offset = kNoPresence; + if (required) { + field->offset = kRequiredPresence; } - upb_FixLocale(buf); } -void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size) { - assert(size >= kUpb_RoundTripBufferSize); - snprintf(buf, size, "%.*g", FLT_DIG, val); - if (strtof(buf, NULL) != val) { - snprintf(buf, size, "%.*g", FLT_DIG + 3, val); - assert(strtof(buf, NULL) == val); +static void upb_MtDecoder_PushItem(upb_MtDecoder* d, upb_LayoutItem item) { + if (d->vec.size == d->vec.capacity) { + size_t new_cap = UPB_MAX(8, d->vec.size * 2); + d->vec.data = realloc(d->vec.data, new_cap * sizeof(*d->vec.data)); + upb_MtDecoder_CheckOutOfMemory(d, d->vec.data); + d->vec.capacity = new_cap; } - upb_FixLocale(buf); + d->vec.data[d->vec.size++] = item; } -/** upb/decode_fast.c ************************************************************/ -// Fast decoder: ~3x the speed of decode.c, but requires x86-64/ARM64. -// Also the table size grows by 2x. -// -// Could potentially be ported to other 64-bit archs that pass at least six -// arguments in registers and have 8 unused high bits in pointers. -// -// The overall design is to create specialized functions for every possible -// field type (eg. oneof boolean field with a 1 byte tag) and then dispatch -// to the specialized function as quickly as possible. - - - -/* Must be last. */ - -#if UPB_FASTTABLE +static void upb_MtDecoder_PushOneof(upb_MtDecoder* d, upb_LayoutItem item) { + if (item.field_index == kUpb_LayoutItem_IndexSentinel) { + upb_MtDecoder_ErrorFormat(d, "Empty oneof"); + UPB_UNREACHABLE(); + } + item.field_index -= kOneofBase; -// The standard set of arguments passed to each parsing function. -// Thanks to x86-64 calling conventions, these will stay in registers. -#define UPB_PARSE_PARAMS \ - upb_Decoder *d, const char *ptr, upb_Message *msg, intptr_t table, \ - uint64_t hasbits, uint64_t data + // Push oneof data. + item.type = kUpb_LayoutItemType_OneofField; + upb_MtDecoder_PushItem(d, item); -#define UPB_PARSE_ARGS d, ptr, msg, table, hasbits, data + // Push oneof case. + item.rep = kUpb_FieldRep_4Byte; // Field Number. + item.type = kUpb_LayoutItemType_OneofCase; + upb_MtDecoder_PushItem(d, item); +} -#define RETURN_GENERIC(m) \ - /* Uncomment either of these for debugging purposes. */ \ - /* fprintf(stderr, m); */ \ - /*__builtin_trap(); */ \ - return fastdecode_generic(d, ptr, msg, table, hasbits, 0); +size_t upb_MtDecoder_SizeOfRep(upb_FieldRep rep, + upb_MiniTablePlatform platform) { + static const uint8_t kRepToSize32[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 4, [kUpb_FieldRep_StringView] = 8, + [kUpb_FieldRep_8Byte] = 8, + }; + static const uint8_t kRepToSize64[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 8, [kUpb_FieldRep_StringView] = 16, + [kUpb_FieldRep_8Byte] = 8, + }; + UPB_ASSERT(sizeof(upb_StringView) == + UPB_SIZE(kRepToSize32, kRepToSize64)[kUpb_FieldRep_StringView]); + return platform == kUpb_MiniTablePlatform_32Bit ? kRepToSize32[rep] + : kRepToSize64[rep]; +} + +size_t upb_MtDecoder_AlignOfRep(upb_FieldRep rep, + upb_MiniTablePlatform platform) { + static const uint8_t kRepToAlign32[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 4, [kUpb_FieldRep_StringView] = 4, + [kUpb_FieldRep_8Byte] = 8, + }; + static const uint8_t kRepToAlign64[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 8, [kUpb_FieldRep_StringView] = 8, + [kUpb_FieldRep_8Byte] = 8, + }; + UPB_ASSERT(UPB_ALIGN_OF(upb_StringView) == + UPB_SIZE(kRepToAlign32, kRepToAlign64)[kUpb_FieldRep_StringView]); + return platform == kUpb_MiniTablePlatform_32Bit ? kRepToAlign32[rep] + : kRepToAlign64[rep]; +} + +static const char* upb_MtDecoder_DecodeOneofField(upb_MtDecoder* d, + const char* ptr, + char first_ch, + upb_LayoutItem* item) { + uint32_t field_num; + ptr = upb_MiniTable_DecodeBase92Varint( + d, ptr, first_ch, kUpb_EncodedValue_MinOneofField, + kUpb_EncodedValue_MaxOneofField, &field_num); + upb_MiniTable_Field* f = + (void*)upb_MiniTable_FindFieldByNumber(d->table, field_num); -typedef enum { - CARD_s = 0, /* Singular (optional, non-repeated) */ - CARD_o = 1, /* Oneof */ - CARD_r = 2, /* Repeated */ - CARD_p = 3 /* Packed Repeated */ -} upb_card; + if (!f) { + upb_MtDecoder_ErrorFormat(d, + "Couldn't add field number %" PRIu32 + " to oneof, no such field number.", + field_num); + UPB_UNREACHABLE(); + } + if (f->offset != kHasbitPresence) { + upb_MtDecoder_ErrorFormat( + d, + "Cannot add repeated, required, or singular field %" PRIu32 + " to oneof.", + field_num); + UPB_UNREACHABLE(); + } -UPB_NOINLINE -static const char* fastdecode_isdonefallback(UPB_PARSE_PARAMS) { - int overrun = data; - int status; - ptr = decode_isdonefallback_inl(d, ptr, overrun, &status); - if (ptr == NULL) { - return fastdecode_err(d, status); + // Oneof storage must be large enough to accommodate the largest member. + int rep = f->mode >> kUpb_FieldRep_Shift; + if (upb_MtDecoder_SizeOfRep(rep, d->platform) > + upb_MtDecoder_SizeOfRep(item->rep, d->platform)) { + item->rep = rep; } - data = fastdecode_loadtag(ptr); - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); + // Prepend this field to the linked list. + f->offset = item->field_index; + item->field_index = (f - d->fields) + kOneofBase; + return ptr; } -UPB_FORCEINLINE -static const char* fastdecode_dispatch(UPB_PARSE_PARAMS) { - if (UPB_UNLIKELY(ptr >= d->limit_ptr)) { - int overrun = ptr - d->end; - if (UPB_LIKELY(overrun == d->limit)) { - // Parse is finished. - *(uint32_t*)msg |= hasbits; // Sync hasbits. - const upb_MiniTable* l = decode_totablep(table); - return UPB_UNLIKELY(l->required_count) - ? decode_checkrequired(d, ptr, msg, l) - : ptr; +static const char* upb_MtDecoder_DecodeOneofs(upb_MtDecoder* d, + const char* ptr) { + upb_LayoutItem item = {.rep = 0, + .field_index = kUpb_LayoutItem_IndexSentinel}; + while (ptr < d->end) { + char ch = *ptr++; + if (ch == kUpb_EncodedValue_FieldSeparator) { + // Field separator, no action needed. + } else if (ch == kUpb_EncodedValue_OneofSeparator) { + // End of oneof. + upb_MtDecoder_PushOneof(d, item); + item.field_index = kUpb_LayoutItem_IndexSentinel; // Move to next oneof. } else { - data = overrun; - UPB_MUSTTAIL return fastdecode_isdonefallback(UPB_PARSE_ARGS); + ptr = upb_MtDecoder_DecodeOneofField(d, ptr, ch, &item); } } - // Read two bytes of tag data (for a one-byte tag, the high byte is junk). - data = fastdecode_loadtag(ptr); - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); + // Push final oneof. + upb_MtDecoder_PushOneof(d, item); + return ptr; } -UPB_FORCEINLINE -static bool fastdecode_checktag(uint16_t data, int tagbytes) { - if (tagbytes == 1) { - return (data & 0xff) == 0; +static const char* upb_MtDecoder_ParseModifier(upb_MtDecoder* d, + const char* ptr, char first_ch, + upb_MiniTable_Field* last_field, + uint64_t* msg_modifiers) { + uint32_t mod; + ptr = upb_MiniTable_DecodeBase92Varint(d, ptr, first_ch, + kUpb_EncodedValue_MinModifier, + kUpb_EncodedValue_MaxModifier, &mod); + if (last_field) { + upb_MtDecoder_ModifyField(d, *msg_modifiers, mod, last_field); } else { - return data == 0; + if (!d->table) { + upb_MtDecoder_ErrorFormat(d, "Extensions cannot have message modifiers"); + UPB_UNREACHABLE(); + } + *msg_modifiers = mod; } + + return ptr; } -UPB_FORCEINLINE -static const char* fastdecode_longsize(const char* ptr, int* size) { - int i; - UPB_ASSERT(*size & 0x80); - *size &= 0xff; - for (i = 0; i < 3; i++) { - ptr++; - size_t byte = (uint8_t)ptr[-1]; - *size += (byte - 1) << (7 + 7 * i); - if (UPB_LIKELY((byte & 0x80) == 0)) return ptr; +static void upb_MtDecoder_AllocateSubs(upb_MtDecoder* d, uint32_t sub_count) { + size_t subs_bytes = sizeof(*d->table->subs) * sub_count; + d->table->subs = upb_Arena_Malloc(d->arena, subs_bytes); + upb_MtDecoder_CheckOutOfMemory(d, d->table->subs); +} + +static const char* upb_MtDecoder_Parse(upb_MtDecoder* d, const char* ptr, + size_t len, void* fields, + size_t field_size, uint16_t* field_count, + uint32_t* sub_count) { + uint64_t msg_modifiers = 0; + uint32_t last_field_number = 0; + upb_MiniTable_Field* last_field = NULL; + bool need_dense_below = d->table != NULL; + + d->end = UPB_PTRADD(ptr, len); + + while (ptr < d->end) { + char ch = *ptr++; + if (ch <= kUpb_EncodedValue_MaxField) { + if (!d->table && last_field) { + // For extensions, consume only a single field and then return. + return --ptr; + } + upb_MiniTable_Field* field = fields; + *field_count += 1; + fields = (char*)fields + field_size; + field->number = ++last_field_number; + last_field = field; + upb_MiniTable_SetField(d, ch, field, msg_modifiers, sub_count); + } else if (kUpb_EncodedValue_MinModifier <= ch && + ch <= kUpb_EncodedValue_MaxModifier) { + ptr = upb_MtDecoder_ParseModifier(d, ptr, ch, last_field, &msg_modifiers); + if (msg_modifiers & kUpb_MessageModifier_IsExtendable) { + d->table->ext |= kUpb_ExtMode_Extendable; + } + } else if (ch == kUpb_EncodedValue_End) { + if (!d->table) { + upb_MtDecoder_ErrorFormat(d, "Extensions cannot have oneofs."); + UPB_UNREACHABLE(); + } + ptr = upb_MtDecoder_DecodeOneofs(d, ptr); + } else if (kUpb_EncodedValue_MinSkip <= ch && + ch <= kUpb_EncodedValue_MaxSkip) { + if (need_dense_below) { + d->table->dense_below = d->table->field_count; + need_dense_below = false; + } + uint32_t skip; + ptr = upb_MiniTable_DecodeBase92Varint(d, ptr, ch, + kUpb_EncodedValue_MinSkip, + kUpb_EncodedValue_MaxSkip, &skip); + last_field_number += skip; + last_field_number--; // Next field seen will increment. + } } - ptr++; - size_t byte = (uint8_t)ptr[-1]; - // len is limited by 2gb not 4gb, hence 8 and not 16 as normally expected - // for a 32 bit varint. - if (UPB_UNLIKELY(byte >= 8)) return NULL; - *size += (byte - 1) << 28; + + if (need_dense_below) { + d->table->dense_below = d->table->field_count; + } + return ptr; } -UPB_FORCEINLINE -static bool fastdecode_boundscheck(const char* ptr, size_t len, - const char* end) { - uintptr_t uptr = (uintptr_t)ptr; - uintptr_t uend = (uintptr_t)end + 16; - uintptr_t res = uptr + len; - return res < uptr || res > uend; +static void upb_MtDecoder_ParseMessage(upb_MtDecoder* d, const char* data, + size_t len) { + // Buffer length is an upper bound on the number of fields. We will return + // what we don't use. + d->fields = upb_Arena_Malloc(d->arena, sizeof(*d->fields) * len); + upb_MtDecoder_CheckOutOfMemory(d, d->fields); + + uint32_t sub_count = 0; + d->table->field_count = 0; + d->table->fields = d->fields; + upb_MtDecoder_Parse(d, data, len, d->fields, sizeof(*d->fields), + &d->table->field_count, &sub_count); + + upb_Arena_ShrinkLast(d->arena, d->fields, sizeof(*d->fields) * len, + sizeof(*d->fields) * d->table->field_count); + d->table->fields = d->fields; + upb_MtDecoder_AllocateSubs(d, sub_count); +} + +int upb_MtDecoder_CompareFields(const void* _a, const void* _b) { + const upb_LayoutItem* a = _a; + const upb_LayoutItem* b = _b; + // Currently we just sort by: + // 1. rep (smallest fields first) + // 2. type (oneof cases first) + // 2. field_index (smallest numbers first) + // The main goal of this is to reduce space lost to padding. + // Later we may have more subtle reasons to prefer a different ordering. + const int rep_bits = _upb_Log2Ceiling(kUpb_FieldRep_Max); + const int type_bits = _upb_Log2Ceiling(kUpb_LayoutItemType_Max); + const int idx_bits = (sizeof(a->field_index) * 8); + UPB_ASSERT(idx_bits + rep_bits + type_bits < 32); +#define UPB_COMBINE(rep, ty, idx) (((rep << type_bits) | ty) << idx_bits) | idx + uint32_t a_packed = UPB_COMBINE(a->rep, a->type, a->field_index); + uint32_t b_packed = UPB_COMBINE(b->rep, b->type, b->field_index); + assert(a_packed != b_packed); +#undef UPB_COMBINE + return a_packed < b_packed ? -1 : 1; +} + +static bool upb_MtDecoder_SortLayoutItems(upb_MtDecoder* d) { + // Add items for all non-oneof fields (oneofs were already added). + int n = d->table->field_count; + for (int i = 0; i < n; i++) { + upb_MiniTable_Field* f = &d->fields[i]; + if (f->offset >= kOneofBase) continue; + upb_LayoutItem item = {.field_index = i, + .rep = f->mode >> kUpb_FieldRep_Shift, + .type = kUpb_LayoutItemType_Field}; + upb_MtDecoder_PushItem(d, item); + } + + if (d->vec.size) { + qsort(d->vec.data, d->vec.size, sizeof(*d->vec.data), + upb_MtDecoder_CompareFields); + } + + return true; } -UPB_FORCEINLINE -static bool fastdecode_boundscheck2(const char* ptr, size_t len, - const char* end) { - // This is one extra branch compared to the more normal: - // return (size_t)(end - ptr) < size; - // However it is one less computation if we are just about to use "ptr + len": - // https://godbolt.org/z/35YGPz - // In microbenchmarks this shows an overall 4% improvement. - uintptr_t uptr = (uintptr_t)ptr; - uintptr_t uend = (uintptr_t)end; - uintptr_t res = uptr + len; - return res < uptr || res > uend; +static size_t upb_MiniTable_DivideRoundUp(size_t n, size_t d) { + return (n + d - 1) / d; } -typedef const char* fastdecode_delimfunc(upb_Decoder* d, const char* ptr, - void* ctx); +static void upb_MtDecoder_AssignHasbits(upb_MiniTable* ret) { + int n = ret->field_count; + int last_hasbit = 0; // 0 cannot be used. -UPB_FORCEINLINE -static const char* fastdecode_delimited(upb_Decoder* d, const char* ptr, - fastdecode_delimfunc* func, void* ctx) { - ptr++; - int len = (int8_t)ptr[-1]; - if (fastdecode_boundscheck2(ptr, len, d->limit_ptr)) { - // Slow case: Sub-message is >=128 bytes and/or exceeds the current buffer. - // If it exceeds the buffer limit, limit/limit_ptr will change during - // sub-message parsing, so we need to preserve delta, not limit. - if (UPB_UNLIKELY(len & 0x80)) { - // Size varint >1 byte (length >= 128). - ptr = fastdecode_longsize(ptr, &len); - if (!ptr) { - // Corrupt wire format: size exceeded INT_MAX. - return NULL; - } + // First assign required fields, which must have the lowest hasbits. + for (int i = 0; i < n; i++) { + upb_MiniTable_Field* field = (upb_MiniTable_Field*)&ret->fields[i]; + if (field->offset == kRequiredPresence) { + field->presence = ++last_hasbit; + } else if (field->offset == kNoPresence) { + field->presence = 0; } - if (ptr - d->end + (int)len > d->limit) { - // Corrupt wire format: invalid limit. - return NULL; + } + ret->required_count = last_hasbit; + + // Next assign non-required hasbit fields. + for (int i = 0; i < n; i++) { + upb_MiniTable_Field* field = (upb_MiniTable_Field*)&ret->fields[i]; + if (field->offset == kHasbitPresence) { + field->presence = ++last_hasbit; } - int delta = decode_pushlimit(d, ptr, len); - ptr = func(d, ptr, ctx); - decode_poplimit(d, ptr, delta); - } else { - // Fast case: Sub-message is <128 bytes and fits in the current buffer. - // This means we can preserve limit/limit_ptr verbatim. - const char* saved_limit_ptr = d->limit_ptr; - int saved_limit = d->limit; - d->limit_ptr = ptr + len; - d->limit = d->limit_ptr - d->end; - UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); - ptr = func(d, ptr, ctx); - d->limit_ptr = saved_limit_ptr; - d->limit = saved_limit; - UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); } - return ptr; -} -/* singular, oneof, repeated field handling ***********************************/ + ret->size = last_hasbit ? upb_MiniTable_DivideRoundUp(last_hasbit + 1, 8) : 0; +} + +size_t upb_MtDecoder_Place(upb_MtDecoder* d, upb_FieldRep rep) { + size_t size = upb_MtDecoder_SizeOfRep(rep, d->platform); + size_t align = upb_MtDecoder_AlignOfRep(rep, d->platform); + size_t ret = UPB_ALIGN_UP(d->table->size, align); + static const size_t max = UINT16_MAX; + size_t new_size = ret + size; + if (new_size > max) { + upb_MtDecoder_ErrorFormat( + d, "Message size exceeded maximum size of %zu bytes", max); + } + d->table->size = new_size; + return ret; +} + +static void upb_MtDecoder_AssignOffsets(upb_MtDecoder* d) { + upb_LayoutItem* end = UPB_PTRADD(d->vec.data, d->vec.size); + + // Compute offsets. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + item->offset = upb_MtDecoder_Place(d, item->rep); + } + + // Assign oneof case offsets. We must do these first, since assigning + // actual offsets will overwrite the links of the linked list. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + if (item->type != kUpb_LayoutItemType_OneofCase) continue; + upb_MiniTable_Field* f = &d->fields[item->field_index]; + while (true) { + f->presence = ~item->offset; + if (f->offset == kUpb_LayoutItem_IndexSentinel) break; + UPB_ASSERT(f->offset - kOneofBase < d->table->field_count); + f = &d->fields[f->offset - kOneofBase]; + } + } + + // Assign offsets. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + upb_MiniTable_Field* f = &d->fields[item->field_index]; + switch (item->type) { + case kUpb_LayoutItemType_OneofField: + while (true) { + uint16_t next_offset = f->offset; + f->offset = item->offset; + if (next_offset == kUpb_LayoutItem_IndexSentinel) break; + f = &d->fields[next_offset - kOneofBase]; + } + break; + case kUpb_LayoutItemType_Field: + f->offset = item->offset; + break; + default: + break; + } + } + + // The fasttable parser (supported on 64-bit only) depends on this being a + // multiple of 8 in order to satisfy UPB_MALLOC_ALIGN, which is also 8. + // + // On 32-bit we could potentially make this smaller, but there is no + // compelling reason to optimize this right now. + d->table->size = UPB_ALIGN_UP(d->table->size, 8); +} + +upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, void** buf, + size_t* buf_size, + upb_Status* status) { + upb_MtDecoder decoder = { + .platform = platform, + .vec = + { + .data = *buf, + .capacity = *buf_size / sizeof(*decoder.vec.data), + .size = 0, + }, + .arena = arena, + .status = status, + .table = upb_Arena_Malloc(arena, sizeof(*decoder.table)), + }; + + if (UPB_SETJMP(decoder.err)) { + decoder.table = NULL; + goto done; + } + + upb_MtDecoder_CheckOutOfMemory(&decoder, decoder.table); -typedef struct { - upb_Array* arr; - void* end; -} fastdecode_arr; + decoder.table->size = 0; + decoder.table->field_count = 0; + decoder.table->ext = kUpb_ExtMode_NonExtendable; + decoder.table->dense_below = 0; + decoder.table->table_mask = -1; + decoder.table->required_count = 0; -typedef enum { - FD_NEXT_ATLIMIT, - FD_NEXT_SAMEFIELD, - FD_NEXT_OTHERFIELD -} fastdecode_next; + upb_MtDecoder_ParseMessage(&decoder, data, len); + upb_MtDecoder_AssignHasbits(decoder.table); + upb_MtDecoder_SortLayoutItems(&decoder); + upb_MtDecoder_AssignOffsets(&decoder); -typedef struct { - void* dst; - fastdecode_next next; - uint32_t tag; -} fastdecode_nextret; +done: + *buf = decoder.vec.data; + *buf_size = decoder.vec.capacity * sizeof(*decoder.vec.data); + return decoder.table; +} + +upb_MiniTable* upb_MiniTable_BuildMessageSet(upb_MiniTablePlatform platform, + upb_Arena* arena) { + upb_MiniTable* ret = upb_Arena_Malloc(arena, sizeof(*ret)); + if (!ret) return NULL; + + ret->size = 0; + ret->field_count = 0; + ret->ext = kUpb_ExtMode_IsMessageSet; + ret->dense_below = 0; + ret->table_mask = -1; + ret->required_count = 0; + return ret; +} -UPB_FORCEINLINE -static void* fastdecode_resizearr(upb_Decoder* d, void* dst, - fastdecode_arr* farr, int valbytes) { - if (UPB_UNLIKELY(dst == farr->end)) { - size_t old_size = farr->arr->size; - size_t old_bytes = old_size * valbytes; - size_t new_size = old_size * 2; - size_t new_bytes = new_size * valbytes; - char* old_ptr = _upb_array_ptr(farr->arr); - char* new_ptr = upb_Arena_Realloc(&d->arena, old_ptr, old_bytes, new_bytes); - uint8_t elem_size_lg2 = __builtin_ctz(valbytes); - farr->arr->size = new_size; - farr->arr->data = _upb_array_tagptr(new_ptr, elem_size_lg2); - dst = (void*)(new_ptr + (old_size * valbytes)); - farr->end = (void*)(new_ptr + (new_size * valbytes)); +upb_MiniTable* upb_MiniTable_BuildMapEntry(upb_FieldType key_type, + upb_FieldType value_type, + bool value_is_proto3_enum, + upb_MiniTablePlatform platform, + upb_Arena* arena) { + upb_MiniTable* ret = upb_Arena_Malloc(arena, sizeof(*ret)); + upb_MiniTable_Field* fields = upb_Arena_Malloc(arena, sizeof(*fields) * 2); + if (!ret || !fields) return NULL; + + upb_MiniTable_Sub* subs = NULL; + if (value_is_proto3_enum) value_type = kUpb_FieldType_Int32; + if (value_type == kUpb_FieldType_Message || + value_type == kUpb_FieldType_Group || value_type == kUpb_FieldType_Enum) { + subs = upb_Arena_Malloc(arena, sizeof(*subs)); + if (!subs) return NULL; + } + + size_t field_size = + upb_MtDecoder_SizeOfRep(kUpb_FieldRep_StringView, platform); + + fields[0].number = 1; + fields[1].number = 2; + fields[0].mode = kUpb_FieldMode_Scalar; + fields[1].mode = kUpb_FieldMode_Scalar; + fields[0].presence = 0; + fields[1].presence = 0; + fields[0].offset = 0; + fields[1].offset = field_size; + + upb_MiniTable_SetTypeAndSub(&fields[0], key_type, NULL, 0); + upb_MiniTable_SetTypeAndSub(&fields[1], value_type, NULL, 0); + + ret->size = UPB_ALIGN_UP(2 * field_size, 8); + ret->field_count = 2; + ret->ext = kUpb_ExtMode_NonExtendable | kUpb_ExtMode_IsMapEntry; + ret->dense_below = 2; + ret->table_mask = -1; + ret->required_count = 0; + ret->subs = subs; + ret->fields = fields; + return ret; +} + +static size_t upb_MiniTable_EnumSize(size_t count) { + return sizeof(upb_MiniTable_Enum) + count * sizeof(uint32_t); +} + +static upb_MiniTable_Enum* _upb_MiniTable_AddEnumDataMember(upb_MtDecoder* d, + uint32_t val) { + if (d->enum_data_count == d->enum_data_capacity) { + size_t old_sz = upb_MiniTable_EnumSize(d->enum_data_capacity); + d->enum_data_capacity = UPB_MAX(2, d->enum_data_capacity * 2); + size_t new_sz = upb_MiniTable_EnumSize(d->enum_data_capacity); + d->enum_table = upb_Arena_Realloc(d->arena, d->enum_table, old_sz, new_sz); + upb_MtDecoder_CheckOutOfMemory(d, d->enum_table); } - return dst; + d->enum_table->data[d->enum_data_count++] = val; + return d->enum_table; } -UPB_FORCEINLINE -static bool fastdecode_tagmatch(uint32_t tag, uint64_t data, int tagbytes) { - if (tagbytes == 1) { - return (uint8_t)tag == (uint8_t)data; +static void upb_MiniTable_BuildEnumValue(upb_MtDecoder* d, uint32_t val) { + upb_MiniTable_Enum* table = d->enum_table; + d->enum_value_count++; + if (table->value_count || (val > 512 && d->enum_value_count < val / 32)) { + if (table->value_count == 0) { + assert(d->enum_data_count == table->mask_limit / 32); + } + table = _upb_MiniTable_AddEnumDataMember(d, val); + table->value_count++; } else { - return (uint16_t)tag == (uint16_t)data; + uint32_t new_mask_limit = ((val / 32) + 1) * 32; + while (table->mask_limit < new_mask_limit) { + table = _upb_MiniTable_AddEnumDataMember(d, 0); + table->mask_limit += 32; + } + table->data[val / 32] |= 1ULL << (val % 32); + } +} + +upb_MiniTable_Enum* upb_MiniTable_BuildEnum(const char* data, size_t len, + upb_Arena* arena, + upb_Status* status) { + upb_MtDecoder d = { + .enum_table = upb_Arena_Malloc(arena, upb_MiniTable_EnumSize(2)), + .enum_value_count = 0, + .enum_data_count = 0, + .enum_data_capacity = 1, + .status = status, + .end = UPB_PTRADD(data, len), + .arena = arena, + }; + + if (UPB_SETJMP(d.err)) { + return NULL; } -} -UPB_FORCEINLINE -static void fastdecode_commitarr(void* dst, fastdecode_arr* farr, - int valbytes) { - farr->arr->len = - (size_t)((char*)dst - (char*)_upb_array_ptr(farr->arr)) / valbytes; -} + upb_MtDecoder_CheckOutOfMemory(&d, d.enum_table); -UPB_FORCEINLINE -static fastdecode_nextret fastdecode_nextrepeated(upb_Decoder* d, void* dst, - const char** ptr, - fastdecode_arr* farr, - uint64_t data, int tagbytes, - int valbytes) { - fastdecode_nextret ret; - dst = (char*)dst + valbytes; + // Guarantee at least 64 bits of mask without checking mask size. + d.enum_table->mask_limit = 64; + d.enum_table = _upb_MiniTable_AddEnumDataMember(&d, 0); + d.enum_table = _upb_MiniTable_AddEnumDataMember(&d, 0); - if (UPB_LIKELY(!decode_isdone(d, ptr))) { - ret.tag = fastdecode_loadtag(*ptr); - if (fastdecode_tagmatch(ret.tag, data, tagbytes)) { - ret.next = FD_NEXT_SAMEFIELD; + d.enum_table->value_count = 0; + + const char* ptr = data; + uint32_t base = 0; + + while (ptr < d.end) { + char ch = *ptr++; + if (ch <= kUpb_EncodedValue_MaxEnumMask) { + uint32_t mask = upb_FromBase92(ch); + for (int i = 0; i < 5; i++, base++, mask >>= 1) { + if (mask & 1) upb_MiniTable_BuildEnumValue(&d, base); + } + } else if (kUpb_EncodedValue_MinSkip <= ch && + ch <= kUpb_EncodedValue_MaxSkip) { + uint32_t skip; + ptr = upb_MiniTable_DecodeBase92Varint(&d, ptr, ch, + kUpb_EncodedValue_MinSkip, + kUpb_EncodedValue_MaxSkip, &skip); + base += skip; } else { - fastdecode_commitarr(dst, farr, valbytes); - ret.next = FD_NEXT_OTHERFIELD; + upb_Status_SetErrorFormat(status, "Unexpected character: %c", ch); + return NULL; } - } else { - fastdecode_commitarr(dst, farr, valbytes); - ret.next = FD_NEXT_ATLIMIT; } - ret.dst = dst; + return d.enum_table; +} + +const char* upb_MiniTable_BuildExtension(const char* data, size_t len, + upb_MiniTable_Extension* ext, + const upb_MiniTable* extendee, + upb_MiniTable_Sub sub, + upb_Status* status) { + upb_MtDecoder decoder = { + .arena = NULL, + .status = status, + .table = NULL, + }; + + if (UPB_SETJMP(decoder.err)) { + return NULL; + } + + uint16_t count = 0; + const char* ret = + upb_MtDecoder_Parse(&decoder, data, len, ext, sizeof(*ext), &count, NULL); + if (!ret || count != 1) return NULL; + + upb_MiniTable_Field* f = &ext->field; + + f->mode |= kUpb_LabelFlags_IsExtension; + f->offset = 0; + f->presence = 0; + + if (extendee->ext & kUpb_ExtMode_IsMessageSet) { + // Extensions of MessageSet must be messages. + if (!upb_IsSubMessage(f)) return NULL; + + // Extensions of MessageSet must be non-repeating. + if ((f->mode & kUpb_FieldMode_Mask) == kUpb_FieldMode_Array) return NULL; + } + + ext->extendee = extendee; + ext->sub = sub; + return ret; } -UPB_FORCEINLINE -static void* fastdecode_fieldmem(upb_Message* msg, uint64_t data) { - size_t ofs = data >> 48; - return (char*)msg + ofs; +upb_MiniTable* upb_MiniTable_Build(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, upb_Status* status) { + void* buf = NULL; + size_t size = 0; + upb_MiniTable* ret = upb_MiniTable_BuildWithBuf(data, len, platform, arena, + &buf, &size, status); + free(buf); + return ret; } -UPB_FORCEINLINE -static void* fastdecode_getfield(upb_Decoder* d, const char* ptr, - upb_Message* msg, uint64_t* data, - uint64_t* hasbits, fastdecode_arr* farr, - int valbytes, upb_card card) { - switch (card) { - case CARD_s: { - uint8_t hasbit_index = *data >> 24; - // Set hasbit and return pointer to scalar field. - *hasbits |= 1ull << hasbit_index; - return fastdecode_fieldmem(msg, *data); - } - case CARD_o: { - uint16_t case_ofs = *data >> 32; - uint32_t* oneof_case = UPB_PTR_AT(msg, case_ofs, uint32_t); - uint8_t field_number = *data >> 24; - *oneof_case = field_number; - return fastdecode_fieldmem(msg, *data); - } - case CARD_r: { - // Get pointer to upb_Array and allocate/expand if necessary. - uint8_t elem_size_lg2 = __builtin_ctz(valbytes); - upb_Array** arr_p = fastdecode_fieldmem(msg, *data); - char* begin; - *(uint32_t*)msg |= *hasbits; - *hasbits = 0; - if (UPB_LIKELY(!*arr_p)) { - farr->arr = _upb_Array_New(&d->arena, 8, elem_size_lg2); - *arr_p = farr->arr; - } else { - farr->arr = *arr_p; - } - begin = _upb_array_ptr(farr->arr); - farr->end = begin + (farr->arr->size * valbytes); - *data = fastdecode_loadtag(ptr); - return begin + (farr->arr->len * valbytes); - } - default: - UPB_UNREACHABLE(); +void upb_MiniTable_SetSubMessage(upb_MiniTable* table, + upb_MiniTable_Field* field, + const upb_MiniTable* sub) { + UPB_ASSERT((uintptr_t)table->fields <= (uintptr_t)field && + (uintptr_t)field < + (uintptr_t)(table->fields + table->field_count)); + if (sub->ext & kUpb_ExtMode_IsMapEntry) { + field->mode = + (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift) | kUpb_FieldMode_Map; } + upb_MiniTable_Sub* table_sub = (void*)&table->subs[field->submsg_index]; + table_sub->submsg = sub; } -UPB_FORCEINLINE -static bool fastdecode_flippacked(uint64_t* data, int tagbytes) { - *data ^= (0x2 ^ 0x0); // Patch data to match packed wiretype. - return fastdecode_checktag(*data, tagbytes); +void upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTable_Field* field, + const upb_MiniTable_Enum* sub) { + UPB_ASSERT((uintptr_t)table->fields <= (uintptr_t)field && + (uintptr_t)field < + (uintptr_t)(table->fields + table->field_count)); + upb_MiniTable_Sub* table_sub = (void*)&table->subs[field->submsg_index]; + table_sub->subenum = sub; } -#define FASTDECODE_CHECKPACKED(tagbytes, card, func) \ - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ - if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) { \ - UPB_MUSTTAIL return func(UPB_PARSE_ARGS); \ - } \ - RETURN_GENERIC("packed check tag mismatch\n"); \ - } -/* varint fields **************************************************************/ +#include -UPB_FORCEINLINE -static uint64_t fastdecode_munge(uint64_t val, int valbytes, bool zigzag) { - if (valbytes == 1) { - return val != 0; - } else if (zigzag) { - if (valbytes == 4) { - uint32_t n = val; - return (n >> 1) ^ -(int32_t)(n & 1); - } else if (valbytes == 8) { - return (val >> 1) ^ -(int64_t)(val & 1); - } - UPB_UNREACHABLE(); + +// Must be last. + +/* The upb core does not generally have a concept of default instances. However + * for descriptor options we make an exception since the max size is known and + * modest (<200 bytes). All types can share a default instance since it is + * initialized to zeroes. + * + * We have to allocate an extra pointer for upb's internal metadata. */ +static const char opt_default_buf[_UPB_MAXOPT_SIZE + sizeof(void*)] = {0}; +const char* kUpbDefOptDefault = &opt_default_buf[sizeof(void*)]; + +const char* _upb_DefBuilder_FullToShort(const char* fullname) { + const char* p; + + if (fullname == NULL) { + return NULL; + } else if ((p = strrchr(fullname, '.')) == NULL) { + /* No '.' in the name, return the full string. */ + return fullname; + } else { + /* Return one past the last '.'. */ + return p + 1; } - return val; } -UPB_FORCEINLINE -static const char* fastdecode_varint64(const char* ptr, uint64_t* val) { - ptr++; - *val = (uint8_t)ptr[-1]; - if (UPB_UNLIKELY(*val & 0x80)) { - int i; - for (i = 0; i < 8; i++) { - ptr++; - uint64_t byte = (uint8_t)ptr[-1]; - *val += (byte - 1) << (7 + 7 * i); - if (UPB_LIKELY((byte & 0x80) == 0)) goto done; - } - ptr++; - uint64_t byte = (uint8_t)ptr[-1]; - if (byte > 1) { - return NULL; - } - *val += (byte - 1) << 63; - } -done: - UPB_ASSUME(ptr != NULL); - return ptr; +void _upb_DefBuilder_FailJmp(upb_DefBuilder* ctx) { UPB_LONGJMP(ctx->err, 1); } + +void _upb_DefBuilder_Errf(upb_DefBuilder* ctx, const char* fmt, ...) { + va_list argp; + va_start(argp, fmt); + upb_Status_VSetErrorFormat(ctx->status, fmt, argp); + va_end(argp); + _upb_DefBuilder_FailJmp(ctx); } -#define FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, zigzag, packed) \ - uint64_t val; \ - void* dst; \ - fastdecode_arr farr; \ - \ - FASTDECODE_CHECKPACKED(tagbytes, card, packed); \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ - card); \ - if (card == CARD_r) { \ - if (UPB_UNLIKELY(!dst)) { \ - RETURN_GENERIC("need array resize\n"); \ - } \ - } \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ - } \ - \ - ptr += tagbytes; \ - ptr = fastdecode_varint64(ptr, &val); \ - if (ptr == NULL) return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - val = fastdecode_munge(val, valbytes, zigzag); \ - memcpy(dst, &val, valbytes); \ - \ - if (card == CARD_r) { \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, valbytes); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +void _upb_DefBuilder_OomErr(upb_DefBuilder* ctx) { + upb_Status_SetErrorMessage(ctx->status, "out of memory"); + _upb_DefBuilder_FailJmp(ctx); +} -typedef struct { - uint8_t valbytes; - bool zigzag; - void* dst; - fastdecode_arr farr; -} fastdecode_varintdata; +const char* _upb_DefBuilder_MakeFullName(upb_DefBuilder* ctx, + const char* prefix, + upb_StringView name) { + if (prefix) { + // ret = prefix + '.' + name; + size_t n = strlen(prefix); + char* ret = _upb_DefBuilder_Alloc(ctx, n + name.size + 2); + strcpy(ret, prefix); + ret[n] = '.'; + memcpy(&ret[n + 1], name.data, name.size); + ret[n + 1 + name.size] = '\0'; + return ret; + } else { + char* ret = upb_strdup2(name.data, name.size, ctx->arena); + if (!ret) _upb_DefBuilder_OomErr(ctx); + return ret; + } +} -UPB_FORCEINLINE -static const char* fastdecode_topackedvarint(upb_Decoder* d, const char* ptr, - void* ctx) { - fastdecode_varintdata* data = ctx; - void* dst = data->dst; - uint64_t val; +static bool remove_component(char* base, size_t* len) { + if (*len == 0) return false; - while (!decode_isdone(d, &ptr)) { - dst = fastdecode_resizearr(d, dst, &data->farr, data->valbytes); - ptr = fastdecode_varint64(ptr, &val); - if (ptr == NULL) return NULL; - val = fastdecode_munge(val, data->valbytes, data->zigzag); - memcpy(dst, &val, data->valbytes); - dst = (char*)dst + data->valbytes; + for (size_t i = *len - 1; i > 0; i--) { + if (base[i] == '.') { + *len = i; + return true; + } } - fastdecode_commitarr(dst, &data->farr, data->valbytes); - return ptr; + *len = 0; + return true; } -#define FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, zigzag, unpacked) \ - fastdecode_varintdata ctx = {valbytes, zigzag}; \ - \ - FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked); \ - \ - ctx.dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &ctx.farr, \ - valbytes, CARD_r); \ - if (UPB_UNLIKELY(!ctx.dst)) { \ - RETURN_GENERIC("need array resize\n"); \ - } \ - \ - ptr += tagbytes; \ - ptr = fastdecode_delimited(d, ptr, &fastdecode_topackedvarint, &ctx); \ - \ - if (UPB_UNLIKELY(ptr == NULL)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(d, ptr, msg, table, hasbits, 0); - -#define FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, zigzag, unpacked, packed) \ - if (card == CARD_p) { \ - FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, zigzag, unpacked); \ - } else { \ - FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, zigzag, packed); \ +const void* _upb_DefBuilder_ResolveAny(upb_DefBuilder* ctx, + const char* from_name_dbg, + const char* base, upb_StringView sym, + upb_deftype_t* type) { + if (sym.size == 0) goto notfound; + upb_value v; + if (sym.data[0] == '.') { + /* Symbols starting with '.' are absolute, so we do a single lookup. + * Slice to omit the leading '.' */ + if (!_upb_DefPool_LookupSym(ctx->symtab, sym.data + 1, sym.size - 1, &v)) { + goto notfound; + } + } else { + /* Remove components from base until we find an entry or run out. */ + size_t baselen = base ? strlen(base) : 0; + char* tmp = malloc(sym.size + baselen + 1); + while (1) { + char* p = tmp; + if (baselen) { + memcpy(p, base, baselen); + p[baselen] = '.'; + p += baselen + 1; + } + memcpy(p, sym.data, sym.size); + p += sym.size; + if (_upb_DefPool_LookupSym(ctx->symtab, tmp, p - tmp, &v)) { + break; + } + if (!remove_component(tmp, &baselen)) { + free(tmp); + goto notfound; + } + } + free(tmp); } -#define z_ZZ true -#define b_ZZ false -#define v_ZZ false + *type = _upb_DefType_Type(v); + return _upb_DefType_Unpack(v, *type); -/* Generate all combinations: - * {s,o,r,p} x {b1,v4,z4,v8,z8} x {1bt,2bt} */ +notfound: + _upb_DefBuilder_Errf(ctx, "couldn't resolve name '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(sym)); +} -#define F(card, type, valbytes, tagbytes) \ - UPB_NOINLINE \ - const char* upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ - CARD_##card, type##_ZZ, \ - upb_pr##type##valbytes##_##tagbytes##bt, \ - upb_pp##type##valbytes##_##tagbytes##bt); \ +const void* _upb_DefBuilder_Resolve(upb_DefBuilder* ctx, + const char* from_name_dbg, const char* base, + upb_StringView sym, upb_deftype_t type) { + upb_deftype_t found_type; + const void* ret = + _upb_DefBuilder_ResolveAny(ctx, from_name_dbg, base, sym, &found_type); + if (ret && found_type != type) { + _upb_DefBuilder_Errf(ctx, + "type mismatch when resolving %s: couldn't find " + "name " UPB_STRINGVIEW_FORMAT " with type=%d", + from_name_dbg, UPB_STRINGVIEW_ARGS(sym), (int)type); } + return ret; +} -#define TYPES(card, tagbytes) \ - F(card, b, 1, tagbytes) \ - F(card, v, 4, tagbytes) \ - F(card, v, 8, tagbytes) \ - F(card, z, 4, tagbytes) \ - F(card, z, 8, tagbytes) +// Per ASCII this will lower-case a letter. If the result is a letter, the +// input was definitely a letter. If the output is not a letter, this may +// have transformed the character unpredictably. +static char upb_ascii_lower(char ch) { return ch | 0x20; } -#define TAGBYTES(card) \ - TYPES(card, 1) \ - TYPES(card, 2) +// isalpha() etc. from are locale-dependent, which we don't want. +static bool upb_isbetween(uint8_t c, uint8_t low, uint8_t high) { + return low <= c && c <= high; +} -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) -TAGBYTES(p) +static bool upb_isletter(char c) { + char lower = upb_ascii_lower(c); + return upb_isbetween(lower, 'a', 'z') || c == '_'; +} -#undef z_ZZ -#undef b_ZZ -#undef v_ZZ -#undef o_ONEOF -#undef s_ONEOF -#undef r_ONEOF -#undef F -#undef TYPES -#undef TAGBYTES -#undef FASTDECODE_UNPACKEDVARINT -#undef FASTDECODE_PACKEDVARINT -#undef FASTDECODE_VARINT +static bool upb_isalphanum(char c) { + return upb_isletter(c) || upb_isbetween(c, '0', '9'); +} -/* fixed fields ***************************************************************/ +static bool TryGetChar(const char** src, const char* end, char* ch) { + if (*src == end) return false; + *ch = **src; + *src += 1; + return true; +} -#define FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, packed) \ - void* dst; \ - fastdecode_arr farr; \ - \ - FASTDECODE_CHECKPACKED(tagbytes, card, packed) \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ - card); \ - if (card == CARD_r) { \ - if (UPB_UNLIKELY(!dst)) { \ - RETURN_GENERIC("couldn't allocate array in arena\n"); \ - } \ - } \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ - } \ - \ - ptr += tagbytes; \ - memcpy(dst, ptr, valbytes); \ - ptr += valbytes; \ - \ - if (card == CARD_r) { \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, valbytes); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +static char TryGetHexDigit(const char** src, const char* end) { + char ch; + if (!TryGetChar(src, end, &ch)) return -1; + if ('0' <= ch && ch <= '9') { + return ch - '0'; + } + ch = upb_ascii_lower(ch); + if ('a' <= ch && ch <= 'f') { + return ch - 'a' + 0xa; + } + *src -= 1; // Char wasn't actually a hex digit. + return -1; +} -#define FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, unpacked) \ - FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked) \ - \ - ptr += tagbytes; \ - int size = (uint8_t)ptr[0]; \ - ptr++; \ - if (size & 0x80) { \ - ptr = fastdecode_longsize(ptr, &size); \ - } \ - \ - if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr) || \ - (size % valbytes) != 0)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - \ - upb_Array** arr_p = fastdecode_fieldmem(msg, data); \ - upb_Array* arr = *arr_p; \ - uint8_t elem_size_lg2 = __builtin_ctz(valbytes); \ - int elems = size / valbytes; \ - \ - if (UPB_LIKELY(!arr)) { \ - *arr_p = arr = _upb_Array_New(&d->arena, elems, elem_size_lg2); \ - if (!arr) { \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - } else { \ - _upb_Array_Resize(arr, elems, &d->arena); \ - } \ - \ - char* dst = _upb_array_ptr(arr); \ - memcpy(dst, ptr, size); \ - arr->len = elems; \ - \ - ptr += size; \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +static char upb_DefBuilder_ParseHexEscape(upb_DefBuilder* ctx, + const upb_FieldDef* f, + const char** src, const char* end) { + char hex_digit = TryGetHexDigit(src, end); + if (hex_digit < 0) { + _upb_DefBuilder_Errf( + ctx, "\\x cannot be followed by non-hex digit in field '%s' default", + upb_FieldDef_FullName(f)); + return 0; + } + unsigned int ret = hex_digit; + while ((hex_digit = TryGetHexDigit(src, end)) >= 0) { + ret = (ret << 4) | hex_digit; + } + if (ret > 0xff) { + _upb_DefBuilder_Errf(ctx, "Value of hex escape in field %s exceeds 8 bits", + upb_FieldDef_FullName(f)); + return 0; + } + return ret; +} -#define FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, unpacked, packed) \ - if (card == CARD_p) { \ - FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, unpacked); \ - } else { \ - FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, packed); \ +static char TryGetOctalDigit(const char** src, const char* end) { + char ch; + if (!TryGetChar(src, end, &ch)) return -1; + if ('0' <= ch && ch <= '7') { + return ch - '0'; } + *src -= 1; // Char wasn't actually an octal digit. + return -1; +} -/* Generate all combinations: - * {s,o,r,p} x {f4,f8} x {1bt,2bt} */ +static char upb_DefBuilder_ParseOctalEscape(upb_DefBuilder* ctx, + const upb_FieldDef* f, + const char** src, const char* end) { + char ch = 0; + for (int i = 0; i < 3; i++) { + char digit; + if ((digit = TryGetOctalDigit(src, end)) >= 0) { + ch = (ch << 3) | digit; + } + } + return ch; +} -#define F(card, valbytes, tagbytes) \ - UPB_NOINLINE \ - const char* upb_p##card##f##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ - CARD_##card, upb_ppf##valbytes##_##tagbytes##bt, \ - upb_prf##valbytes##_##tagbytes##bt); \ +char _upb_DefBuilder_ParseEscape(upb_DefBuilder* ctx, const upb_FieldDef* f, + const char** src, const char* end) { + char ch; + if (!TryGetChar(src, end, &ch)) { + _upb_DefBuilder_Errf(ctx, "unterminated escape sequence in field %s", + upb_FieldDef_FullName(f)); + return 0; + } + switch (ch) { + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case '\\': + return '\\'; + case '\'': + return '\''; + case '\"': + return '\"'; + case '?': + return '\?'; + case 'x': + case 'X': + return upb_DefBuilder_ParseHexEscape(ctx, f, src, end); + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + *src -= 1; + return upb_DefBuilder_ParseOctalEscape(ctx, f, src, end); } + _upb_DefBuilder_Errf(ctx, "Unknown escape sequence: \\%c", ch); +} -#define TYPES(card, tagbytes) \ - F(card, 4, tagbytes) \ - F(card, 8, tagbytes) +void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name, + bool full) { + const char* str = name.data; + const size_t len = name.size; + bool start = true; + for (size_t i = 0; i < len; i++) { + const char c = str[i]; + if (c == '.') { + if (start || !full) { + _upb_DefBuilder_Errf( + ctx, "invalid name: unexpected '.' (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } + start = true; + } else if (start) { + if (!upb_isletter(c)) { + _upb_DefBuilder_Errf(ctx, + "invalid name: path components must start with a " + "letter (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } + start = false; + } else if (!upb_isalphanum(c)) { + _upb_DefBuilder_Errf( + ctx, + "invalid name: non-alphanumeric character (" UPB_STRINGVIEW_FORMAT + ")", + UPB_STRINGVIEW_ARGS(name)); + } + } + if (start) { + _upb_DefBuilder_Errf(ctx, + "invalid name: empty part (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } -#define TAGBYTES(card) \ - TYPES(card, 1) \ - TYPES(card, 2) + // We should never reach this point. + UPB_ASSERT(false); +} -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) -TAGBYTES(p) -#undef F -#undef TYPES -#undef TAGBYTES -#undef FASTDECODE_UNPACKEDFIXED -#undef FASTDECODE_PACKEDFIXED -/* string fields **************************************************************/ +// Must be last. -typedef const char* fastdecode_copystr_func(struct upb_Decoder* d, - const char* ptr, upb_Message* msg, - const upb_MiniTable* table, - uint64_t hasbits, - upb_StringView* dst); +struct upb_DefPool { + upb_Arena* arena; + upb_strtable syms; // full_name -> packed def ptr + upb_strtable files; // file_name -> (upb_FileDef*) + upb_inttable exts; // (upb_MiniTable_Extension*) -> (upb_FieldDef*) + upb_ExtensionRegistry* extreg; + void* scratch_data; + size_t scratch_size; + size_t bytes_loaded; +}; -UPB_NOINLINE -static const char* fastdecode_verifyutf8(upb_Decoder* d, const char* ptr, - upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t data) { - upb_StringView* dst = (upb_StringView*)data; - if (!decode_verifyutf8_inl(dst->data, dst->size)) { - return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8); - } - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +void upb_DefPool_Free(upb_DefPool* s) { + upb_Arena_Free(s->arena); + upb_gfree(s->scratch_data); + upb_gfree(s); } -#define FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, validate_utf8) \ - int size = (uint8_t)ptr[0]; /* Could plumb through hasbits. */ \ - ptr++; \ - if (size & 0x80) { \ - ptr = fastdecode_longsize(ptr, &size); \ - } \ - \ - if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr))) { \ - dst->size = 0; \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - \ - if (d->options & kUpb_DecodeOption_AliasString) { \ - dst->data = ptr; \ - dst->size = size; \ - } else { \ - char* data = upb_Arena_Malloc(&d->arena, size); \ - if (!data) { \ - return fastdecode_err(d, kUpb_DecodeStatus_OutOfMemory); \ - } \ - memcpy(data, ptr, size); \ - dst->data = data; \ - dst->size = size; \ - } \ - \ - ptr += size; \ - if (validate_utf8) { \ - data = (uint64_t)dst; \ - UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ - } else { \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ - } +upb_DefPool* upb_DefPool_New(void) { + upb_DefPool* s = upb_gmalloc(sizeof(*s)); + if (!s) return NULL; -UPB_NOINLINE -static const char* fastdecode_longstring_utf8(struct upb_Decoder* d, - const char* ptr, upb_Message* msg, - intptr_t table, uint64_t hasbits, - uint64_t data) { - upb_StringView* dst = (upb_StringView*)data; - FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, true); -} + s->arena = upb_Arena_New(); + s->bytes_loaded = 0; -UPB_NOINLINE -static const char* fastdecode_longstring_noutf8( - struct upb_Decoder* d, const char* ptr, upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t data) { - upb_StringView* dst = (upb_StringView*)data; - FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, false); -} + s->scratch_size = 240; + s->scratch_data = upb_gmalloc(s->scratch_size); + if (!s->scratch_data) goto err; -UPB_FORCEINLINE -static void fastdecode_docopy(upb_Decoder* d, const char* ptr, uint32_t size, - int copy, char* data, upb_StringView* dst) { - d->arena.head.ptr += copy; - dst->data = data; - UPB_UNPOISON_MEMORY_REGION(data, copy); - memcpy(data, ptr, copy); - UPB_POISON_MEMORY_REGION(data + size, copy - size); + if (!upb_strtable_init(&s->syms, 32, s->arena)) goto err; + if (!upb_strtable_init(&s->files, 4, s->arena)) goto err; + if (!upb_inttable_init(&s->exts, s->arena)) goto err; + + s->extreg = upb_ExtensionRegistry_New(s->arena); + if (!s->extreg) goto err; + + return s; + +err: + upb_DefPool_Free(s); + return NULL; } -#define FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ - card, validate_utf8) \ - upb_StringView* dst; \ - fastdecode_arr farr; \ - int64_t size; \ - size_t arena_has; \ - size_t common_has; \ - char* buf; \ - \ - UPB_ASSERT((d->options & kUpb_DecodeOption_AliasString) == 0); \ - UPB_ASSERT(fastdecode_checktag(data, tagbytes)); \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ - sizeof(upb_StringView), card); \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView)); \ - } \ - \ - size = (uint8_t)ptr[tagbytes]; \ - ptr += tagbytes + 1; \ - dst->size = size; \ - \ - buf = d->arena.head.ptr; \ - arena_has = _upb_ArenaHas(&d->arena); \ - common_has = UPB_MIN(arena_has, (d->end - ptr) + 16); \ - \ - if (UPB_LIKELY(size <= 15 - tagbytes)) { \ - if (arena_has < 16) goto longstr; \ - d->arena.head.ptr += 16; \ - memcpy(buf, ptr - tagbytes - 1, 16); \ - dst->data = buf + tagbytes + 1; \ - } else if (UPB_LIKELY(size <= 32)) { \ - if (UPB_UNLIKELY(common_has < 32)) goto longstr; \ - fastdecode_docopy(d, ptr, size, 32, buf, dst); \ - } else if (UPB_LIKELY(size <= 64)) { \ - if (UPB_UNLIKELY(common_has < 64)) goto longstr; \ - fastdecode_docopy(d, ptr, size, 64, buf, dst); \ - } else if (UPB_LIKELY(size < 128)) { \ - if (UPB_UNLIKELY(common_has < 128)) goto longstr; \ - fastdecode_docopy(d, ptr, size, 128, buf, dst); \ - } else { \ - goto longstr; \ - } \ - \ - ptr += size; \ - \ - if (card == CARD_r) { \ - if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8); \ - } \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView)); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - if (card != CARD_r && validate_utf8) { \ - data = (uint64_t)dst; \ - UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ - \ - longstr: \ - if (card == CARD_r) { \ - fastdecode_commitarr(dst + 1, &farr, sizeof(upb_StringView)); \ - } \ - ptr--; \ - if (validate_utf8) { \ - UPB_MUSTTAIL return fastdecode_longstring_utf8(d, ptr, msg, table, \ - hasbits, (uint64_t)dst); \ - } else { \ - UPB_MUSTTAIL return fastdecode_longstring_noutf8(d, ptr, msg, table, \ - hasbits, (uint64_t)dst); \ +bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTable_Extension* ext, + upb_FieldDef* f) { + return upb_inttable_insert(&s->exts, (uintptr_t)ext, upb_value_constptr(f), + s->arena); +} + +bool _upb_DefPool_InsertSym(upb_DefPool* s, upb_StringView sym, upb_value v, + upb_Status* status) { + // TODO: table should support an operation "tryinsert" to avoid the double + // lookup. + if (upb_strtable_lookup2(&s->syms, sym.data, sym.size, NULL)) { + upb_Status_SetErrorFormat(status, "duplicate symbol '%s'", sym.data); + return false; + } + if (!upb_strtable_insert(&s->syms, sym.data, sym.size, v, s->arena)) { + upb_Status_SetErrorMessage(status, "out of memory"); + return false; } + return true; +} -#define FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, card, \ - copyfunc, validate_utf8) \ - upb_StringView* dst; \ - fastdecode_arr farr; \ - int64_t size; \ - \ - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ - RETURN_GENERIC("string field tag mismatch\n"); \ - } \ - \ - if (UPB_UNLIKELY((d->options & kUpb_DecodeOption_AliasString) == 0)) { \ - UPB_MUSTTAIL return copyfunc(UPB_PARSE_ARGS); \ - } \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ - sizeof(upb_StringView), card); \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView)); \ - } \ - \ - size = (int8_t)ptr[tagbytes]; \ - ptr += tagbytes + 1; \ - dst->data = ptr; \ - dst->size = size; \ - \ - if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->end))) { \ - ptr--; \ - if (validate_utf8) { \ - return fastdecode_longstring_utf8(d, ptr, msg, table, hasbits, \ - (uint64_t)dst); \ - } else { \ - return fastdecode_longstring_noutf8(d, ptr, msg, table, hasbits, \ - (uint64_t)dst); \ - } \ - } \ - \ - ptr += size; \ - \ - if (card == CARD_r) { \ - if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8); \ - } \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView)); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - if (UPB_UNLIKELY((d->options & kUpb_DecodeOption_AliasString) == 0)) { \ - /* Buffer flipped and we can't alias any more. Bounce to */ \ - /* copyfunc(), but via dispatch since we need to reload table */ \ - /* data also. */ \ - fastdecode_commitarr(dst, &farr, sizeof(upb_StringView)); \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - } \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - if (card != CARD_r && validate_utf8) { \ - data = (uint64_t)dst; \ - UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +static const void* _upb_DefPool_Unpack(const upb_DefPool* s, const char* sym, + size_t size, upb_deftype_t type) { + upb_value v; + return upb_strtable_lookup2(&s->syms, sym, size, &v) + ? _upb_DefType_Unpack(v, type) + : NULL; +} -/* Generate all combinations: - * {p,c} x {s,o,r} x {s, b} x {1bt,2bt} */ +bool _upb_DefPool_LookupSym(const upb_DefPool* s, const char* sym, size_t size, + upb_value* v) { + return upb_strtable_lookup2(&s->syms, sym, size, v); +} -#define s_VALIDATE true -#define b_VALIDATE false +upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s) { + return s->extreg; +} -#define F(card, tagbytes, type) \ - UPB_NOINLINE \ - const char* upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ - CARD_##card, type##_VALIDATE); \ - } \ - const char* upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, \ - CARD_##card, upb_c##card##type##_##tagbytes##bt, \ - type##_VALIDATE); \ - } +void** _upb_DefPool_ScratchData(const upb_DefPool* s) { + return (void**)&s->scratch_data; +} -#define UTF8(card, tagbytes) \ - F(card, tagbytes, s) \ - F(card, tagbytes, b) +size_t* _upb_DefPool_ScratchSize(const upb_DefPool* s) { + return (size_t*)&s->scratch_size; +} -#define TAGBYTES(card) \ - UTF8(card, 1) \ - UTF8(card, 2) +const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, + const char* sym) { + return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_MSG); +} -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) +const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( + const upb_DefPool* s, const char* sym, size_t len) { + return _upb_DefPool_Unpack(s, sym, len, UPB_DEFTYPE_MSG); +} -#undef s_VALIDATE -#undef b_VALIDATE -#undef F -#undef TAGBYTES -#undef FASTDECODE_LONGSTRING -#undef FASTDECODE_COPYSTRING -#undef FASTDECODE_STRING +const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, + const char* sym) { + return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_ENUM); +} -/* message fields *************************************************************/ +const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, + const char* sym) { + return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_ENUMVAL); +} -UPB_INLINE -upb_Message* decode_newmsg_ceil(upb_Decoder* d, const upb_MiniTable* l, - int msg_ceil_bytes) { - size_t size = l->size + sizeof(upb_Message_Internal); - char* msg_data; - if (UPB_LIKELY(msg_ceil_bytes > 0 && - _upb_ArenaHas(&d->arena) >= msg_ceil_bytes)) { - UPB_ASSERT(size <= (size_t)msg_ceil_bytes); - msg_data = d->arena.head.ptr; - d->arena.head.ptr += size; - UPB_UNPOISON_MEMORY_REGION(msg_data, msg_ceil_bytes); - memset(msg_data, 0, msg_ceil_bytes); - UPB_POISON_MEMORY_REGION(msg_data + size, msg_ceil_bytes - size); - } else { - msg_data = (char*)upb_Arena_Malloc(&d->arena, size); - memset(msg_data, 0, size); - } - return msg_data + sizeof(upb_Message_Internal); +const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, + const char* name) { + upb_value v; + return upb_strtable_lookup(&s->files, name, &v) ? upb_value_getconstptr(v) + : NULL; } -typedef struct { - intptr_t table; - upb_Message* msg; -} fastdecode_submsgdata; +const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, + const char* name, + size_t len) { + upb_value v; + return upb_strtable_lookup2(&s->files, name, len, &v) + ? upb_value_getconstptr(v) + : NULL; +} -UPB_FORCEINLINE -static const char* fastdecode_tosubmsg(upb_Decoder* d, const char* ptr, - void* ctx) { - fastdecode_submsgdata* submsg = ctx; - ptr = fastdecode_dispatch(d, ptr, submsg->msg, submsg->table, 0, 0); - UPB_ASSUME(ptr != NULL); - return ptr; +const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( + const upb_DefPool* s, const char* name, size_t size) { + upb_value v; + if (!upb_strtable_lookup2(&s->syms, name, size, &v)) return NULL; + + switch (_upb_DefType_Type(v)) { + case UPB_DEFTYPE_FIELD: + return _upb_DefType_Unpack(v, UPB_DEFTYPE_FIELD); + case UPB_DEFTYPE_MSG: { + const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); + return _upb_MessageDef_InMessageSet(m) + ? upb_MessageDef_NestedExtension(m, 0) + : NULL; + } + default: + break; + } + + return NULL; } -#define FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, \ - msg_ceil_bytes, card) \ - \ - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ - RETURN_GENERIC("submessage field tag mismatch\n"); \ - } \ - \ - if (--d->depth == 0) { \ - return fastdecode_err(d, kUpb_DecodeStatus_MaxDepthExceeded); \ - } \ - \ - upb_Message** dst; \ - uint32_t submsg_idx = (data >> 16) & 0xff; \ - const upb_MiniTable* tablep = decode_totablep(table); \ - const upb_MiniTable* subtablep = tablep->subs[submsg_idx].submsg; \ - fastdecode_submsgdata submsg = {decode_totable(subtablep)}; \ - fastdecode_arr farr; \ - \ - if (subtablep->table_mask == (uint8_t)-1) { \ - RETURN_GENERIC("submessage doesn't have fast tables."); \ - } \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ - sizeof(upb_Message*), card); \ - \ - if (card == CARD_s) { \ - *(uint32_t*)msg |= hasbits; \ - hasbits = 0; \ - } \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_Message*)); \ - } \ - \ - submsg.msg = *dst; \ - \ - if (card == CARD_r || UPB_LIKELY(!submsg.msg)) { \ - *dst = submsg.msg = decode_newmsg_ceil(d, subtablep, msg_ceil_bytes); \ - } \ - \ - ptr += tagbytes; \ - ptr = fastdecode_delimited(d, ptr, fastdecode_tosubmsg, &submsg); \ - \ - if (UPB_UNLIKELY(ptr == NULL || d->end_group != DECODE_NOGROUP)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - \ - if (card == CARD_r) { \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_Message*)); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - d->depth++; \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - d->depth++; \ - return ptr; \ - } \ - } \ - \ - d->depth++; \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, + const char* sym) { + return upb_DefPool_FindExtensionByNameWithSize(s, sym, strlen(sym)); +} + +const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, + const char* name) { + return _upb_DefPool_Unpack(s, name, strlen(name), UPB_DEFTYPE_SERVICE); +} -#define F(card, tagbytes, size_ceil, ceil_arg) \ - const char* upb_p##card##m_##tagbytes##bt_max##size_ceil##b( \ - UPB_PARSE_PARAMS) { \ - FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, ceil_arg, \ - CARD_##card); \ +const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( + const upb_DefPool* s, const char* name, size_t size) { + return _upb_DefPool_Unpack(s, name, size, UPB_DEFTYPE_SERVICE); +} + +const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, + const char* name) { + upb_value v; + // TODO(haberman): non-extension fields and oneofs. + if (upb_strtable_lookup(&s->syms, name, &v)) { + switch (_upb_DefType_Type(v)) { + case UPB_DEFTYPE_EXT: { + const upb_FieldDef* f = _upb_DefType_Unpack(v, UPB_DEFTYPE_EXT); + return upb_FieldDef_File(f); + } + case UPB_DEFTYPE_MSG: { + const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); + return upb_MessageDef_File(m); + } + case UPB_DEFTYPE_ENUM: { + const upb_EnumDef* e = _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUM); + return upb_EnumDef_File(e); + } + case UPB_DEFTYPE_ENUMVAL: { + const upb_EnumValueDef* ev = + _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUMVAL); + return upb_EnumDef_File(upb_EnumValueDef_Enum(ev)); + } + case UPB_DEFTYPE_SERVICE: { + const upb_ServiceDef* service = + _upb_DefType_Unpack(v, UPB_DEFTYPE_SERVICE); + return upb_ServiceDef_File(service); + } + default: + UPB_UNREACHABLE(); + } } -#define SIZES(card, tagbytes) \ - F(card, tagbytes, 64, 64) \ - F(card, tagbytes, 128, 128) \ - F(card, tagbytes, 192, 192) \ - F(card, tagbytes, 256, 256) \ - F(card, tagbytes, max, -1) + const char* last_dot = strrchr(name, '.'); + if (last_dot) { + const upb_MessageDef* parent = + upb_DefPool_FindMessageByNameWithSize(s, name, last_dot - name); + if (parent) { + const char* shortname = last_dot + 1; + if (upb_MessageDef_FindByNameWithSize(parent, shortname, + strlen(shortname), NULL, NULL)) { + return upb_MessageDef_File(parent); + } + } + } -#define TAGBYTES(card) \ - SIZES(card, 1) \ - SIZES(card, 2) + return NULL; +} -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) +static void remove_filedef(upb_DefPool* s, upb_FileDef* file) { + intptr_t iter = UPB_INTTABLE_BEGIN; + upb_StringView key; + upb_value val; + while (upb_strtable_next2(&s->syms, &key, &val, &iter)) { + const upb_FileDef* f; + switch (_upb_DefType_Type(val)) { + case UPB_DEFTYPE_EXT: + f = upb_FieldDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_EXT)); + break; + case UPB_DEFTYPE_MSG: + f = upb_MessageDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_MSG)); + break; + case UPB_DEFTYPE_ENUM: + f = upb_EnumDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_ENUM)); + break; + case UPB_DEFTYPE_ENUMVAL: + f = upb_EnumDef_File(upb_EnumValueDef_Enum( + _upb_DefType_Unpack(val, UPB_DEFTYPE_ENUMVAL))); + break; + case UPB_DEFTYPE_SERVICE: + f = upb_ServiceDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_SERVICE)); + break; + default: + UPB_UNREACHABLE(); + } -#undef TAGBYTES -#undef SIZES -#undef F -#undef FASTDECODE_SUBMSG + if (f == file) upb_strtable_removeiter(&s->syms, &iter); + } +} -#endif /* UPB_FASTTABLE */ +static const upb_FileDef* _upb_DefPool_AddFile( + upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, + const upb_MiniTable_File* layout, upb_Status* status) { + const upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto); -/** bazel-out/k8-fastbuild/bin/external/com_google_protobuf/google/protobuf/descriptor.upb.c ************************************************************//* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/descriptor.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ + if (name.size == 0) { + upb_Status_SetErrorFormat(status, + "missing name in google_protobuf_FileDescriptorProto"); + return NULL; + } -#include + // Determine whether we already know about this file. + { + upb_value v; + if (upb_strtable_lookup2(&s->files, name.data, name.size, &v)) { + upb_Status_SetErrorFormat(status, + "duplicate file name " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(name)); + return NULL; + } + } + upb_DefBuilder ctx = { + .symtab = s, + .layout = layout, + .msg_count = 0, + .enum_count = 0, + .ext_count = 0, + .status = status, + .file = NULL, + .arena = upb_Arena_New(), + .tmp_arena = upb_Arena_New(), + }; -static const upb_MiniTable_Sub google_protobuf_FileDescriptorSet_submsgs[1] = { - {.submsg = &google_protobuf_FileDescriptorProto_msginit}, -}; + if (UPB_SETJMP(ctx.err)) { + UPB_ASSERT(!upb_Status_IsOk(status)); + if (ctx.file) { + remove_filedef(s, ctx.file); + ctx.file = NULL; + } + } else if (!ctx.arena || !ctx.tmp_arena) { + _upb_DefBuilder_OomErr(&ctx); + } else { + _upb_FileDef_Create(&ctx, file_proto); + upb_strtable_insert(&s->files, name.data, name.size, + upb_value_constptr(ctx.file), ctx.arena); + UPB_ASSERT(upb_Status_IsOk(status)); + upb_Arena_Fuse(s->arena, ctx.arena); + } -static const upb_MiniTable_Field google_protobuf_FileDescriptorSet__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; + if (ctx.arena) upb_Arena_Free(ctx.arena); + if (ctx.tmp_arena) upb_Arena_Free(ctx.tmp_arena); + return ctx.file; +} -const upb_MiniTable google_protobuf_FileDescriptorSet_msginit = { - &google_protobuf_FileDescriptorSet_submsgs[0], - &google_protobuf_FileDescriptorSet__fields[0], - UPB_SIZE(8, 8), 1, upb_ExtMode_NonExtendable, 1, 255, 0, -}; +const upb_FileDef* upb_DefPool_AddFile( + upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, + upb_Status* status) { + return _upb_DefPool_AddFile(s, file_proto, NULL, status); +} -static const upb_MiniTable_Sub google_protobuf_FileDescriptorProto_submsgs[6] = { - {.submsg = &google_protobuf_DescriptorProto_msginit}, - {.submsg = &google_protobuf_EnumDescriptorProto_msginit}, - {.submsg = &google_protobuf_FieldDescriptorProto_msginit}, - {.submsg = &google_protobuf_FileOptions_msginit}, - {.submsg = &google_protobuf_ServiceDescriptorProto_msginit}, - {.submsg = &google_protobuf_SourceCodeInfo_msginit}, -}; +/* Include here since we want most of this file to be stdio-free. */ +#include -static const upb_MiniTable_Field google_protobuf_FileDescriptorProto__fields[12] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {3, UPB_SIZE(36, 72), 0, 0, 12, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {4, UPB_SIZE(40, 80), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {5, UPB_SIZE(44, 88), 0, 1, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {6, UPB_SIZE(48, 96), 0, 4, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {7, UPB_SIZE(52, 104), 0, 2, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {8, UPB_SIZE(28, 56), 3, 3, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {9, UPB_SIZE(32, 64), 4, 5, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {10, UPB_SIZE(56, 112), 0, 0, 5, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {11, UPB_SIZE(60, 120), 0, 0, 5, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {12, UPB_SIZE(20, 40), 5, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, -}; +bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, + bool rebuild_minitable) { + /* Since this function should never fail (it would indicate a bug in upb) we + * print errors to stderr instead of returning error status to the user. */ + _upb_DefPool_Init** deps = init->deps; + google_protobuf_FileDescriptorProto* file; + upb_Arena* arena; + upb_Status status; -const upb_MiniTable google_protobuf_FileDescriptorProto_msginit = { - &google_protobuf_FileDescriptorProto_submsgs[0], - &google_protobuf_FileDescriptorProto__fields[0], - UPB_SIZE(64, 128), 12, upb_ExtMode_NonExtendable, 12, 255, 0, -}; + upb_Status_Clear(&status); -static const upb_MiniTable_Sub google_protobuf_DescriptorProto_submsgs[7] = { - {.submsg = &google_protobuf_DescriptorProto_msginit}, - {.submsg = &google_protobuf_DescriptorProto_ExtensionRange_msginit}, - {.submsg = &google_protobuf_DescriptorProto_ReservedRange_msginit}, - {.submsg = &google_protobuf_EnumDescriptorProto_msginit}, - {.submsg = &google_protobuf_FieldDescriptorProto_msginit}, - {.submsg = &google_protobuf_MessageOptions_msginit}, - {.submsg = &google_protobuf_OneofDescriptorProto_msginit}, -}; + if (upb_DefPool_FindFileByName(s, init->filename)) { + return true; + } -static const upb_MiniTable_Field google_protobuf_DescriptorProto__fields[10] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(16, 32), 0, 4, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {3, UPB_SIZE(20, 40), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {4, UPB_SIZE(24, 48), 0, 3, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {5, UPB_SIZE(28, 56), 0, 1, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {6, UPB_SIZE(32, 64), 0, 4, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {7, UPB_SIZE(12, 24), 2, 5, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {8, UPB_SIZE(36, 72), 0, 6, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {9, UPB_SIZE(40, 80), 0, 2, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {10, UPB_SIZE(44, 88), 0, 0, 12, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; + arena = upb_Arena_New(); -const upb_MiniTable google_protobuf_DescriptorProto_msginit = { - &google_protobuf_DescriptorProto_submsgs[0], - &google_protobuf_DescriptorProto__fields[0], - UPB_SIZE(48, 96), 10, upb_ExtMode_NonExtendable, 10, 255, 0, -}; + for (; *deps; deps++) { + if (!_upb_DefPool_LoadDefInitEx(s, *deps, rebuild_minitable)) goto err; + } -static const upb_MiniTable_Sub google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = { - {.submsg = &google_protobuf_ExtensionRangeOptions_msginit}, -}; + file = google_protobuf_FileDescriptorProto_parse_ex( + init->descriptor.data, init->descriptor.size, NULL, + kUpb_DecodeOption_AliasString, arena); + s->bytes_loaded += init->descriptor.size; -static const upb_MiniTable_Field google_protobuf_DescriptorProto_ExtensionRange__fields[3] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 16), 3, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; + if (!file) { + upb_Status_SetErrorFormat( + &status, + "Failed to parse compiled-in descriptor for file '%s'. This should " + "never happen.", + init->filename); + goto err; + } -const upb_MiniTable google_protobuf_DescriptorProto_ExtensionRange_msginit = { - &google_protobuf_DescriptorProto_ExtensionRange_submsgs[0], - &google_protobuf_DescriptorProto_ExtensionRange__fields[0], - UPB_SIZE(16, 24), 3, upb_ExtMode_NonExtendable, 3, 255, 0, -}; + const upb_MiniTable_File* mt = rebuild_minitable ? NULL : init->layout; + if (!_upb_DefPool_AddFile(s, file, mt, &status)) { + goto err; + } -static const upb_MiniTable_Field google_protobuf_DescriptorProto_ReservedRange__fields[2] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, -}; + upb_Arena_Free(arena); + return true; -const upb_MiniTable google_protobuf_DescriptorProto_ReservedRange_msginit = { - NULL, - &google_protobuf_DescriptorProto_ReservedRange__fields[0], - UPB_SIZE(16, 16), 2, upb_ExtMode_NonExtendable, 2, 255, 0, -}; +err: + fprintf(stderr, + "Error loading compiled-in descriptor for file '%s' (this should " + "never happen): %s\n", + init->filename, upb_Status_ErrorMessage(&status)); + upb_Arena_Free(arena); + return false; +} -static const upb_MiniTable_Sub google_protobuf_ExtensionRangeOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; +size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s) { + return s->bytes_loaded; +} -static const upb_MiniTable_Field google_protobuf_ExtensionRangeOptions__fields[1] = { - {999, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; +upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s) { return s->arena; } -const upb_MiniTable google_protobuf_ExtensionRangeOptions_msginit = { - &google_protobuf_ExtensionRangeOptions_submsgs[0], - &google_protobuf_ExtensionRangeOptions__fields[0], - UPB_SIZE(8, 8), 1, upb_ExtMode_Extendable, 0, 255, 0, -}; +const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable( + const upb_DefPool* s, const upb_MiniTable_Extension* ext) { + upb_value v; + bool ok = upb_inttable_lookup(&s->exts, (uintptr_t)ext, &v); + UPB_ASSERT(ok); + return upb_value_getconstptr(v); +} -static const upb_MiniTable_Sub google_protobuf_FieldDescriptorProto_submsgs[3] = { - {.submsg = &google_protobuf_FieldOptions_msginit}, - {.subenum = &google_protobuf_FieldDescriptorProto_Label_enuminit}, - {.subenum = &google_protobuf_FieldDescriptorProto_Type_enuminit}, -}; +const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, + const upb_MessageDef* m, + int32_t fieldnum) { + const upb_MiniTable* l = upb_MessageDef_MiniTable(m); + const upb_MiniTable_Extension* ext = _upb_extreg_get(s->extreg, l, fieldnum); + return ext ? _upb_DefPool_FindExtensionByMiniTable(s, ext) : NULL; +} -static const upb_MiniTable_Field google_protobuf_FieldDescriptorProto__fields[11] = { - {1, UPB_SIZE(24, 24), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(32, 40), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 12), 3, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {4, UPB_SIZE(4, 4), 4, 1, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {5, UPB_SIZE(8, 8), 5, 2, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {6, UPB_SIZE(40, 56), 6, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {7, UPB_SIZE(48, 72), 7, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {8, UPB_SIZE(64, 104), 8, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {9, UPB_SIZE(16, 16), 9, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {10, UPB_SIZE(56, 88), 10, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {17, UPB_SIZE(20, 20), 11, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, -}; +const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( + const upb_DefPool* s) { + return s->extreg; +} -const upb_MiniTable google_protobuf_FieldDescriptorProto_msginit = { - &google_protobuf_FieldDescriptorProto_submsgs[0], - &google_protobuf_FieldDescriptorProto__fields[0], - UPB_SIZE(72, 112), 11, upb_ExtMode_NonExtendable, 10, 255, 0, -}; +const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, + const upb_MessageDef* m, + size_t* count) { + size_t n = 0; + intptr_t iter = UPB_INTTABLE_BEGIN; + uintptr_t key; + upb_value val; + // This is O(all exts) instead of O(exts for m). If we need this to be + // efficient we may need to make extreg into a two-level table, or have a + // second per-message index. + while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { + const upb_FieldDef* f = upb_value_getconstptr(val); + if (upb_FieldDef_ContainingType(f) == m) n++; + } + const upb_FieldDef** exts = malloc(n * sizeof(*exts)); + iter = UPB_INTTABLE_BEGIN; + size_t i = 0; + while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { + const upb_FieldDef* f = upb_value_getconstptr(val); + if (upb_FieldDef_ContainingType(f) == m) exts[i++] = f; + } + *count = n; + return exts; +} + +bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init) { + return _upb_DefPool_LoadDefInitEx(s, init, false); +} -static const upb_MiniTable_Sub google_protobuf_OneofDescriptorProto_submsgs[1] = { - {.submsg = &google_protobuf_OneofOptions_msginit}, -}; -static const upb_MiniTable_Field google_protobuf_OneofDescriptorProto__fields[2] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 24), 2, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; +// Must be last. -const upb_MiniTable google_protobuf_OneofDescriptorProto_msginit = { - &google_protobuf_OneofDescriptorProto_submsgs[0], - &google_protobuf_OneofDescriptorProto__fields[0], - UPB_SIZE(16, 32), 2, upb_ExtMode_NonExtendable, 2, 255, 0, -}; +upb_deftype_t _upb_DefType_Type(upb_value v) { + const uintptr_t num = (uintptr_t)upb_value_getconstptr(v); + return num & UPB_DEFTYPE_MASK; +} -static const upb_MiniTable_Sub google_protobuf_EnumDescriptorProto_submsgs[3] = { - {.submsg = &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit}, - {.submsg = &google_protobuf_EnumOptions_msginit}, - {.submsg = &google_protobuf_EnumValueDescriptorProto_msginit}, -}; +upb_value _upb_DefType_Pack(const void* ptr, upb_deftype_t type) { + uintptr_t num = (uintptr_t)ptr; + UPB_ASSERT((num & UPB_DEFTYPE_MASK) == 0); + num |= type; + return upb_value_constptr((const void*)num); +} -static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto__fields[5] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(16, 32), 0, 2, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 24), 2, 1, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {4, UPB_SIZE(20, 40), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {5, UPB_SIZE(24, 48), 0, 0, 12, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; +const void* _upb_DefType_Unpack(upb_value v, upb_deftype_t type) { + uintptr_t num = (uintptr_t)upb_value_getconstptr(v); + return (num & UPB_DEFTYPE_MASK) == type + ? (const void*)(num & ~UPB_DEFTYPE_MASK) + : NULL; +} -const upb_MiniTable google_protobuf_EnumDescriptorProto_msginit = { - &google_protobuf_EnumDescriptorProto_submsgs[0], - &google_protobuf_EnumDescriptorProto__fields[0], - UPB_SIZE(32, 64), 5, upb_ExtMode_NonExtendable, 5, 255, 0, -}; -static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, -}; +// Must be last. -const upb_MiniTable google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit = { - NULL, - &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0], - UPB_SIZE(16, 16), 2, upb_ExtMode_NonExtendable, 2, 255, 0, -}; +bool _upb_DescState_Grow(upb_DescState* d, upb_Arena* a) { + const size_t oldbufsize = d->bufsize; + const int used = d->ptr - d->buf; -static const upb_MiniTable_Sub google_protobuf_EnumValueDescriptorProto_submsgs[1] = { - {.submsg = &google_protobuf_EnumValueOptions_msginit}, -}; + if (!d->buf) { + d->buf = upb_Arena_Malloc(a, d->bufsize); + if (!d->buf) return false; + d->ptr = d->buf; + d->e.end = d->buf + d->bufsize; + } -static const upb_MiniTable_Field google_protobuf_EnumValueDescriptorProto__fields[3] = { - {1, UPB_SIZE(8, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(4, 4), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {3, UPB_SIZE(16, 24), 3, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; + if (oldbufsize - used < kUpb_MtDataEncoder_MinSize) { + d->bufsize *= 2; + d->buf = upb_Arena_Realloc(a, d->buf, oldbufsize, d->bufsize); + if (!d->buf) return false; + d->ptr = d->buf + used; + d->e.end = d->buf + d->bufsize; + } -const upb_MiniTable google_protobuf_EnumValueDescriptorProto_msginit = { - &google_protobuf_EnumValueDescriptorProto_submsgs[0], - &google_protobuf_EnumValueDescriptorProto__fields[0], - UPB_SIZE(24, 32), 3, upb_ExtMode_NonExtendable, 3, 255, 0, -}; + return true; +} -static const upb_MiniTable_Sub google_protobuf_ServiceDescriptorProto_submsgs[2] = { - {.submsg = &google_protobuf_MethodDescriptorProto_msginit}, - {.submsg = &google_protobuf_ServiceOptions_msginit}, -}; -static const upb_MiniTable_Field google_protobuf_ServiceDescriptorProto__fields[3] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(16, 32), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 24), 2, 1, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; +#include -const upb_MiniTable google_protobuf_ServiceDescriptorProto_msginit = { - &google_protobuf_ServiceDescriptorProto_submsgs[0], - &google_protobuf_ServiceDescriptorProto__fields[0], - UPB_SIZE(24, 48), 3, upb_ExtMode_NonExtendable, 3, 255, 0, -}; -static const upb_MiniTable_Sub google_protobuf_MethodDescriptorProto_submsgs[1] = { - {.submsg = &google_protobuf_MethodOptions_msginit}, -}; +// Must be last. -static const upb_MiniTable_Field google_protobuf_MethodDescriptorProto__fields[6] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {3, UPB_SIZE(20, 40), 3, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {4, UPB_SIZE(28, 56), 4, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {5, UPB_SIZE(1, 1), 5, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {6, UPB_SIZE(2, 2), 6, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, +struct upb_EnumDef { + const google_protobuf_EnumOptions* opts; + const upb_MiniTable_Enum* layout; // Only for proto2. + const upb_FileDef* file; + const upb_MessageDef* containing_type; // Could be merged with "file". + const char* full_name; + upb_strtable ntoi; + upb_inttable iton; + const upb_EnumValueDef* values; + int value_count; + int32_t defaultval; + bool is_sorted; // Whether all of the values are defined in ascending order. }; -const upb_MiniTable google_protobuf_MethodDescriptorProto_msginit = { - &google_protobuf_MethodDescriptorProto_submsgs[0], - &google_protobuf_MethodDescriptorProto__fields[0], - UPB_SIZE(32, 64), 6, upb_ExtMode_NonExtendable, 6, 255, 0, -}; +upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i) { + return (upb_EnumDef*)&e[i]; +} -static const upb_MiniTable_Sub google_protobuf_FileOptions_submsgs[2] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, - {.subenum = &google_protobuf_FileOptions_OptimizeMode_enuminit}, -}; +// TODO: Maybe implement this on top of a ZCOS instead? +void _upb_EnumDef_Debug(const upb_EnumDef* e) { + fprintf(stderr, "enum %s (%p) {\n", e->full_name, e); + fprintf(stderr, " value_count: %d\n", e->value_count); + fprintf(stderr, " default: %d\n", e->defaultval); + fprintf(stderr, " is_sorted: %d\n", e->is_sorted); + fprintf(stderr, "}\n"); +} -static const upb_MiniTable_Field google_protobuf_FileOptions__fields[21] = { - {1, UPB_SIZE(20, 24), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {8, UPB_SIZE(28, 40), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {9, UPB_SIZE(4, 4), 3, 1, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {10, UPB_SIZE(8, 8), 4, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {11, UPB_SIZE(36, 56), 5, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {16, UPB_SIZE(9, 9), 6, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {17, UPB_SIZE(10, 10), 7, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {18, UPB_SIZE(11, 11), 8, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {20, UPB_SIZE(12, 12), 9, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {23, UPB_SIZE(13, 13), 10, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {27, UPB_SIZE(14, 14), 11, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {31, UPB_SIZE(15, 15), 12, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {36, UPB_SIZE(44, 72), 13, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {37, UPB_SIZE(52, 88), 14, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {39, UPB_SIZE(60, 104), 15, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {40, UPB_SIZE(68, 120), 16, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {41, UPB_SIZE(76, 136), 17, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {42, UPB_SIZE(16, 16), 18, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {44, UPB_SIZE(84, 152), 19, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {45, UPB_SIZE(92, 168), 20, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {999, UPB_SIZE(100, 184), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; +const upb_MiniTable_Enum* _upb_EnumDef_MiniTable(const upb_EnumDef* e) { + return e->layout; +} -const upb_MiniTable google_protobuf_FileOptions_msginit = { - &google_protobuf_FileOptions_submsgs[0], - &google_protobuf_FileOptions__fields[0], - UPB_SIZE(104, 192), 21, upb_ExtMode_Extendable, 1, 255, 0, -}; +bool _upb_EnumDef_Insert(upb_EnumDef* e, upb_EnumValueDef* v, upb_Arena* a) { + const char* name = upb_EnumValueDef_Name(v); + const upb_value val = upb_value_constptr(v); + bool ok = upb_strtable_insert(&e->ntoi, name, strlen(name), val, a); + if (!ok) return false; -static const upb_MiniTable_Sub google_protobuf_MessageOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; + // Multiple enumerators can have the same number, first one wins. + const int number = upb_EnumValueDef_Number(v); + if (!upb_inttable_lookup(&e->iton, number, NULL)) { + return upb_inttable_insert(&e->iton, number, val, a); + } + return true; +} -static const upb_MiniTable_Field google_protobuf_MessageOptions__fields[5] = { - {1, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {2, UPB_SIZE(2, 2), 2, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {3, UPB_SIZE(3, 3), 3, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {7, UPB_SIZE(4, 4), 4, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {999, UPB_SIZE(8, 8), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; +const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e) { + return e->opts; +} -const upb_MiniTable google_protobuf_MessageOptions_msginit = { - &google_protobuf_MessageOptions_submsgs[0], - &google_protobuf_MessageOptions__fields[0], - UPB_SIZE(16, 16), 5, upb_ExtMode_Extendable, 3, 255, 0, -}; +bool upb_EnumDef_HasOptions(const upb_EnumDef* e) { + return e->opts != (void*)kUpbDefOptDefault; +} -static const upb_MiniTable_Sub google_protobuf_FieldOptions_submsgs[3] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, - {.subenum = &google_protobuf_FieldOptions_CType_enuminit}, - {.subenum = &google_protobuf_FieldOptions_JSType_enuminit}, -}; +const char* upb_EnumDef_FullName(const upb_EnumDef* e) { return e->full_name; } -static const upb_MiniTable_Field google_protobuf_FieldOptions__fields[8] = { - {1, UPB_SIZE(4, 4), 1, 1, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 12), 2, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {3, UPB_SIZE(13, 13), 3, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {5, UPB_SIZE(14, 14), 4, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {6, UPB_SIZE(8, 8), 5, 2, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {10, UPB_SIZE(15, 15), 6, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {15, UPB_SIZE(16, 16), 7, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {999, UPB_SIZE(20, 24), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; +const char* upb_EnumDef_Name(const upb_EnumDef* e) { + return _upb_DefBuilder_FullToShort(e->full_name); +} -const upb_MiniTable google_protobuf_FieldOptions_msginit = { - &google_protobuf_FieldOptions_submsgs[0], - &google_protobuf_FieldOptions__fields[0], - UPB_SIZE(24, 32), 8, upb_ExtMode_Extendable, 3, 255, 0, -}; +const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e) { return e->file; } -static const upb_MiniTable_Sub google_protobuf_OneofOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; +const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e) { + return e->containing_type; +} -static const upb_MiniTable_Field google_protobuf_OneofOptions__fields[1] = { - {999, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; +int32_t upb_EnumDef_Default(const upb_EnumDef* e) { + UPB_ASSERT(upb_EnumDef_FindValueByNumber(e, e->defaultval)); + return e->defaultval; +} -const upb_MiniTable google_protobuf_OneofOptions_msginit = { - &google_protobuf_OneofOptions_submsgs[0], - &google_protobuf_OneofOptions__fields[0], - UPB_SIZE(8, 8), 1, upb_ExtMode_Extendable, 0, 255, 0, -}; +int upb_EnumDef_ValueCount(const upb_EnumDef* e) { return e->value_count; } -static const upb_MiniTable_Sub google_protobuf_EnumOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; +const upb_EnumValueDef* upb_EnumDef_FindValueByName(const upb_EnumDef* e, + const char* name) { + return upb_EnumDef_FindValueByNameWithSize(e, name, strlen(name)); +} -static const upb_MiniTable_Field google_protobuf_EnumOptions__fields[3] = { - {2, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {3, UPB_SIZE(2, 2), 2, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; +const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( + const upb_EnumDef* e, const char* name, size_t size) { + upb_value v; + return upb_strtable_lookup2(&e->ntoi, name, size, &v) + ? upb_value_getconstptr(v) + : NULL; +} -const upb_MiniTable google_protobuf_EnumOptions_msginit = { - &google_protobuf_EnumOptions_submsgs[0], - &google_protobuf_EnumOptions__fields[0], - UPB_SIZE(8, 16), 3, upb_ExtMode_Extendable, 0, 255, 0, -}; +const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* e, + int32_t num) { + upb_value v; + return upb_inttable_lookup(&e->iton, num, &v) ? upb_value_getconstptr(v) + : NULL; +} -static const upb_MiniTable_Sub google_protobuf_EnumValueOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; +bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num) { + // We could use upb_EnumDef_FindValueByNumber(e, num) != NULL, but we expect + // this to be faster (especially for small numbers). + return upb_MiniTable_Enum_CheckValue(e->layout, num); +} -static const upb_MiniTable_Field google_protobuf_EnumValueOptions__fields[2] = { - {1, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; +const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i) { + UPB_ASSERT(0 <= i && i < e->value_count); + return _upb_EnumValueDef_At(e->values, i); +} -const upb_MiniTable google_protobuf_EnumValueOptions_msginit = { - &google_protobuf_EnumValueOptions_submsgs[0], - &google_protobuf_EnumValueOptions__fields[0], - UPB_SIZE(8, 16), 2, upb_ExtMode_Extendable, 1, 255, 0, -}; +bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, + upb_StringView* out) { + upb_DescState s; + _upb_DescState_Init(&s); -static const upb_MiniTable_Sub google_protobuf_ServiceOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; + const upb_EnumValueDef** sorted = NULL; + if (!e->is_sorted) { + sorted = _upb_EnumValueDefs_Sorted(e->values, e->value_count, a); + if (!sorted) return false; + } -static const upb_MiniTable_Field google_protobuf_ServiceOptions__fields[2] = { - {33, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; + upb_MtDataEncoder_StartEnum(&s.e); -const upb_MiniTable google_protobuf_ServiceOptions_msginit = { - &google_protobuf_ServiceOptions_submsgs[0], - &google_protobuf_ServiceOptions__fields[0], - UPB_SIZE(8, 16), 2, upb_ExtMode_Extendable, 0, 255, 0, -}; + // Duplicate values are allowed but we only encode each value once. + uint32_t previous = 0; -static const upb_MiniTable_Sub google_protobuf_MethodOptions_submsgs[2] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, - {.subenum = &google_protobuf_MethodOptions_IdempotencyLevel_enuminit}, -}; + for (size_t i = 0; i < e->value_count; i++) { + const uint32_t current = + upb_EnumValueDef_Number(sorted ? sorted[i] : upb_EnumDef_Value(e, i)); + if (i != 0 && previous == current) continue; -static const upb_MiniTable_Field google_protobuf_MethodOptions__fields[3] = { - {33, UPB_SIZE(8, 8), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {34, UPB_SIZE(4, 4), 2, 1, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {999, UPB_SIZE(12, 16), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_PutEnumValue(&s.e, s.ptr, current); + previous = current; + } -const upb_MiniTable google_protobuf_MethodOptions_msginit = { - &google_protobuf_MethodOptions_submsgs[0], - &google_protobuf_MethodOptions__fields[0], - UPB_SIZE(16, 24), 3, upb_ExtMode_Extendable, 0, 255, 0, -}; + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_EndEnum(&s.e, s.ptr); -static const upb_MiniTable_Sub google_protobuf_UninterpretedOption_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_NamePart_msginit}, -}; + // There will always be room for this '\0' in the encoder buffer because + // kUpb_MtDataEncoder_MinSize is overkill for upb_MtDataEncoder_EndEnum(). + UPB_ASSERT(s.ptr < s.buf + s.bufsize); + *s.ptr = '\0'; -static const upb_MiniTable_Field google_protobuf_UninterpretedOption__fields[7] = { - {2, UPB_SIZE(56, 80), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {3, UPB_SIZE(32, 32), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {4, UPB_SIZE(8, 8), 2, 0, 4, kUpb_FieldMode_Scalar | (upb_FieldRep_8Byte << upb_FieldRep_Shift)}, - {5, UPB_SIZE(16, 16), 3, 0, 3, kUpb_FieldMode_Scalar | (upb_FieldRep_8Byte << upb_FieldRep_Shift)}, - {6, UPB_SIZE(24, 24), 4, 0, 1, kUpb_FieldMode_Scalar | (upb_FieldRep_8Byte << upb_FieldRep_Shift)}, - {7, UPB_SIZE(40, 48), 5, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {8, UPB_SIZE(48, 64), 6, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, -}; + out->data = s.buf; + out->size = s.ptr - s.buf; + return true; +} -const upb_MiniTable google_protobuf_UninterpretedOption_msginit = { - &google_protobuf_UninterpretedOption_submsgs[0], - &google_protobuf_UninterpretedOption__fields[0], - UPB_SIZE(64, 96), 7, upb_ExtMode_NonExtendable, 0, 255, 0, -}; +static upb_MiniTable_Enum* create_enumlayout(upb_DefBuilder* ctx, + const upb_EnumDef* e) { + upb_StringView sv; + bool ok = upb_EnumDef_MiniDescriptorEncode(e, ctx->tmp_arena, &sv); + if (!ok) _upb_DefBuilder_Errf(ctx, "OOM while building enum MiniDescriptor"); -static const upb_MiniTable_Field google_protobuf_UninterpretedOption_NamePart__fields[2] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(1, 1), 2, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, -}; + upb_Status status; + upb_MiniTable_Enum* layout = + upb_MiniTable_BuildEnum(sv.data, sv.size, ctx->arena, &status); + if (!layout) + _upb_DefBuilder_Errf(ctx, "Error building enum MiniTable: %s", status.msg); + return layout; +} -const upb_MiniTable google_protobuf_UninterpretedOption_NamePart_msginit = { - NULL, - &google_protobuf_UninterpretedOption_NamePart__fields[0], - UPB_SIZE(16, 32), 2, upb_ExtMode_NonExtendable, 2, 255, 2, -}; +static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_EnumDescriptorProto* enum_proto, + upb_EnumDef* e) { + const google_protobuf_EnumValueDescriptorProto* const* values; + upb_StringView name; + size_t n; -static const upb_MiniTable_Sub google_protobuf_SourceCodeInfo_submsgs[1] = { - {.submsg = &google_protobuf_SourceCodeInfo_Location_msginit}, -}; + // Must happen before _upb_DefBuilder_Add() + e->file = _upb_DefBuilder_File(ctx); -static const upb_MiniTable_Field google_protobuf_SourceCodeInfo__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; + name = google_protobuf_EnumDescriptorProto_name(enum_proto); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); -const upb_MiniTable google_protobuf_SourceCodeInfo_msginit = { - &google_protobuf_SourceCodeInfo_submsgs[0], - &google_protobuf_SourceCodeInfo__fields[0], - UPB_SIZE(8, 8), 1, upb_ExtMode_NonExtendable, 1, 255, 0, -}; + e->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + _upb_DefBuilder_Add(ctx, e->full_name, + _upb_DefType_Pack(e, UPB_DEFTYPE_ENUM)); -static const upb_MiniTable_Field google_protobuf_SourceCodeInfo_Location__fields[5] = { - {1, UPB_SIZE(20, 40), 0, 0, 5, kUpb_FieldMode_Array | upb_LabelFlags_IsPacked | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {2, UPB_SIZE(24, 48), 0, 0, 5, kUpb_FieldMode_Array | upb_LabelFlags_IsPacked | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {3, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {4, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {6, UPB_SIZE(28, 56), 0, 0, 12, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; + values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n); -const upb_MiniTable google_protobuf_SourceCodeInfo_Location_msginit = { - NULL, - &google_protobuf_SourceCodeInfo_Location__fields[0], - UPB_SIZE(32, 64), 5, upb_ExtMode_NonExtendable, 4, 255, 0, -}; + bool ok = upb_strtable_init(&e->ntoi, n, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); -static const upb_MiniTable_Sub google_protobuf_GeneratedCodeInfo_submsgs[1] = { - {.submsg = &google_protobuf_GeneratedCodeInfo_Annotation_msginit}, -}; + ok = upb_inttable_init(&e->iton, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); -static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; + e->defaultval = 0; + e->value_count = n; + e->values = _upb_EnumValueDefs_New(ctx, prefix, n, values, e, &e->is_sorted); -const upb_MiniTable google_protobuf_GeneratedCodeInfo_msginit = { - &google_protobuf_GeneratedCodeInfo_submsgs[0], - &google_protobuf_GeneratedCodeInfo__fields[0], - UPB_SIZE(8, 8), 1, upb_ExtMode_NonExtendable, 1, 255, 0, -}; + if (n == 0) { + _upb_DefBuilder_Errf(ctx, "enums must contain at least one value (%s)", + e->full_name); + } -static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo_Annotation__fields[4] = { - {1, UPB_SIZE(20, 32), 0, 0, 5, kUpb_FieldMode_Array | upb_LabelFlags_IsPacked | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 16), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {3, UPB_SIZE(4, 4), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {4, UPB_SIZE(8, 8), 3, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, -}; + UBP_DEF_SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); -const upb_MiniTable google_protobuf_GeneratedCodeInfo_Annotation_msginit = { - NULL, - &google_protobuf_GeneratedCodeInfo_Annotation__fields[0], - UPB_SIZE(24, 48), 4, upb_ExtMode_NonExtendable, 4, 255, 0, -}; + upb_inttable_compact(&e->iton, ctx->arena); -static const upb_MiniTable *messages_layout[27] = { - &google_protobuf_FileDescriptorSet_msginit, - &google_protobuf_FileDescriptorProto_msginit, - &google_protobuf_DescriptorProto_msginit, - &google_protobuf_DescriptorProto_ExtensionRange_msginit, - &google_protobuf_DescriptorProto_ReservedRange_msginit, - &google_protobuf_ExtensionRangeOptions_msginit, - &google_protobuf_FieldDescriptorProto_msginit, - &google_protobuf_OneofDescriptorProto_msginit, - &google_protobuf_EnumDescriptorProto_msginit, - &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, - &google_protobuf_EnumValueDescriptorProto_msginit, - &google_protobuf_ServiceDescriptorProto_msginit, - &google_protobuf_MethodDescriptorProto_msginit, - &google_protobuf_FileOptions_msginit, - &google_protobuf_MessageOptions_msginit, - &google_protobuf_FieldOptions_msginit, - &google_protobuf_OneofOptions_msginit, - &google_protobuf_EnumOptions_msginit, - &google_protobuf_EnumValueOptions_msginit, - &google_protobuf_ServiceOptions_msginit, - &google_protobuf_MethodOptions_msginit, - &google_protobuf_UninterpretedOption_msginit, - &google_protobuf_UninterpretedOption_NamePart_msginit, - &google_protobuf_SourceCodeInfo_msginit, - &google_protobuf_SourceCodeInfo_Location_msginit, - &google_protobuf_GeneratedCodeInfo_msginit, - &google_protobuf_GeneratedCodeInfo_Annotation_msginit, -}; + if (upb_FileDef_Syntax(e->file) == kUpb_Syntax_Proto2) { + if (ctx->layout) { + UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count); + e->layout = ctx->layout->enums[ctx->enum_count++]; + } else { + e->layout = create_enumlayout(ctx, e); + } + } else { + e->layout = NULL; + } +} -const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enuminit = { - NULL, - 0x7fffeULL, - 0, -}; +upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, + const google_protobuf_EnumDescriptorProto* const* protos, + const upb_MessageDef* containing_type) { + _upb_DefType_CheckPadding(sizeof(upb_EnumDef)); -const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enuminit = { - NULL, - 0xeULL, - 0, -}; + // If a containing type is defined then get the full name from that. + // Otherwise use the package name from the file def. + const char* name = containing_type ? upb_MessageDef_FullName(containing_type) + : _upb_FileDef_RawPackage(ctx->file); -const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enuminit = { - NULL, - 0xeULL, - 0, -}; + upb_EnumDef* e = _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumDef) * n); + for (size_t i = 0; i < n; i++) { + create_enumdef(ctx, name, protos[i], &e[i]); + e[i].containing_type = containing_type; + } + return e; +} -const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enuminit = { - NULL, - 0x7ULL, - 0, -}; -const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enuminit = { - NULL, - 0x7ULL, - 0, -}; -const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enuminit = { - NULL, - 0x7ULL, - 0, -}; +// Must be last. -static const upb_MiniTable_Enum *enums_layout[6] = { - &google_protobuf_FieldDescriptorProto_Type_enuminit, - &google_protobuf_FieldDescriptorProto_Label_enuminit, - &google_protobuf_FileOptions_OptimizeMode_enuminit, - &google_protobuf_FieldOptions_CType_enuminit, - &google_protobuf_FieldOptions_JSType_enuminit, - &google_protobuf_MethodOptions_IdempotencyLevel_enuminit, +struct upb_EnumValueDef { + const google_protobuf_EnumValueOptions* opts; + const upb_EnumDef* parent; + const char* full_name; + int32_t number; }; -const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout = { - messages_layout, - enums_layout, - NULL, - 27, - 6, - 0, -}; +upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i) { + return (upb_EnumValueDef*)&v[i]; +} +static int _upb_EnumValueDef_Compare(const void* p1, const void* p2) { + const uint32_t v1 = (*(const upb_EnumValueDef**)p1)->number; + const uint32_t v2 = (*(const upb_EnumValueDef**)p2)->number; + return (v1 < v2) ? -1 : (v1 > v2); +} +const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v, + int n, upb_Arena* a) { + // TODO: Try to replace this arena alloc with a persistent scratch buffer. + upb_EnumValueDef** out = + (upb_EnumValueDef**)upb_Arena_Malloc(a, n * sizeof(void*)); + if (!out) return NULL; -/** bazel-out/k8-fastbuild/bin/external/com_google_protobuf/google/protobuf/descriptor.upbdefs.c ************************************************************//* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/descriptor.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ + for (int i = 0; i < n; i++) { + out[i] = (upb_EnumValueDef*)&v[i]; + } + qsort(out, n, sizeof(void*), _upb_EnumValueDef_Compare); + return (const upb_EnumValueDef**)out; +} -static const char descriptor[7667] = {'\n', ' ', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'e', 's', 'c', 'r', 'i', 'p', -'t', 'o', 'r', '.', 'p', 'r', 'o', 't', 'o', '\022', '\017', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', -'f', '\"', 'M', '\n', '\021', 'F', 'i', 'l', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'S', 'e', 't', '\022', '8', '\n', -'\004', 'f', 'i', 'l', 'e', '\030', '\001', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', -'o', 'b', 'u', 'f', '.', 'F', 'i', 'l', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', -'\004', 'f', 'i', 'l', 'e', '\"', '\344', '\004', '\n', '\023', 'F', 'i', 'l', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', -'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', -'\030', '\n', '\007', 'p', 'a', 'c', 'k', 'a', 'g', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\007', 'p', 'a', 'c', 'k', 'a', 'g', 'e', -'\022', '\036', '\n', '\n', 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'y', '\030', '\003', ' ', '\003', '(', '\t', 'R', '\n', 'd', 'e', 'p', -'e', 'n', 'd', 'e', 'n', 'c', 'y', '\022', '+', '\n', '\021', 'p', 'u', 'b', 'l', 'i', 'c', '_', 'd', 'e', 'p', 'e', 'n', 'd', 'e', -'n', 'c', 'y', '\030', '\n', ' ', '\003', '(', '\005', 'R', '\020', 'p', 'u', 'b', 'l', 'i', 'c', 'D', 'e', 'p', 'e', 'n', 'd', 'e', 'n', -'c', 'y', '\022', '\'', '\n', '\017', 'w', 'e', 'a', 'k', '_', 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'y', '\030', '\013', ' ', '\003', -'(', '\005', 'R', '\016', 'w', 'e', 'a', 'k', 'D', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'y', '\022', 'C', '\n', '\014', 'm', 'e', 's', -'s', 'a', 'g', 'e', '_', 't', 'y', 'p', 'e', '\030', '\004', ' ', '\003', '(', '\013', '2', ' ', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', -'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', -'\013', 'm', 'e', 's', 's', 'a', 'g', 'e', 'T', 'y', 'p', 'e', '\022', 'A', '\n', '\t', 'e', 'n', 'u', 'm', '_', 't', 'y', 'p', 'e', -'\030', '\005', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', -'E', 'n', 'u', 'm', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\010', 'e', 'n', 'u', 'm', -'T', 'y', 'p', 'e', '\022', 'A', '\n', '\007', 's', 'e', 'r', 'v', 'i', 'c', 'e', '\030', '\006', ' ', '\003', '(', '\013', '2', '\'', '.', 'g', -'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'D', 'e', 's', -'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\007', 's', 'e', 'r', 'v', 'i', 'c', 'e', '\022', 'C', '\n', '\t', -'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\030', '\007', ' ', '\003', '(', '\013', '2', '%', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', -'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', -'r', 'o', 't', 'o', 'R', '\t', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\022', '6', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', -'s', '\030', '\010', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', -'.', 'F', 'i', 'l', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\022', 'I', '\n', '\020', -'s', 'o', 'u', 'r', 'c', 'e', '_', 'c', 'o', 'd', 'e', '_', 'i', 'n', 'f', 'o', '\030', '\t', ' ', '\001', '(', '\013', '2', '\037', '.', -'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 'o', 'u', 'r', 'c', 'e', 'C', 'o', 'd', -'e', 'I', 'n', 'f', 'o', 'R', '\016', 's', 'o', 'u', 'r', 'c', 'e', 'C', 'o', 'd', 'e', 'I', 'n', 'f', 'o', '\022', '\026', '\n', '\006', -'s', 'y', 'n', 't', 'a', 'x', '\030', '\014', ' ', '\001', '(', '\t', 'R', '\006', 's', 'y', 'n', 't', 'a', 'x', '\"', '\271', '\006', '\n', '\017', -'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', -' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', ';', '\n', '\005', 'f', 'i', 'e', 'l', 'd', '\030', '\002', ' ', '\003', '(', '\013', -'2', '%', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'D', -'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\005', 'f', 'i', 'e', 'l', 'd', '\022', 'C', '\n', '\t', -'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\030', '\006', ' ', '\003', '(', '\013', '2', '%', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', -'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', -'r', 'o', 't', 'o', 'R', '\t', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\022', 'A', '\n', '\013', 'n', 'e', 's', 't', 'e', 'd', -'_', 't', 'y', 'p', 'e', '\030', '\003', ' ', '\003', '(', '\013', '2', ' ', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', -'o', 'b', 'u', 'f', '.', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\n', 'n', 'e', 's', -'t', 'e', 'd', 'T', 'y', 'p', 'e', '\022', 'A', '\n', '\t', 'e', 'n', 'u', 'm', '_', 't', 'y', 'p', 'e', '\030', '\004', ' ', '\003', '(', -'\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'E', 'n', 'u', 'm', 'D', -'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\010', 'e', 'n', 'u', 'm', 'T', 'y', 'p', 'e', '\022', -'X', '\n', '\017', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '_', 'r', 'a', 'n', 'g', 'e', '\030', '\005', ' ', '\003', '(', '\013', '2', -'/', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'e', 's', 'c', 'r', 'i', 'p', -'t', 'o', 'r', 'P', 'r', 'o', 't', 'o', '.', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', 'e', 'R', '\016', -'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', 'e', '\022', 'D', '\n', '\n', 'o', 'n', 'e', 'o', 'f', '_', 'd', -'e', 'c', 'l', '\030', '\010', ' ', '\003', '(', '\013', '2', '%', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', -'u', 'f', '.', 'O', 'n', 'e', 'o', 'f', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\t', -'o', 'n', 'e', 'o', 'f', 'D', 'e', 'c', 'l', '\022', '9', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\007', ' ', '\001', '(', -'\013', '2', '\037', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'M', 'e', 's', 's', 'a', -'g', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\022', 'U', '\n', '\016', 'r', 'e', 's', -'e', 'r', 'v', 'e', 'd', '_', 'r', 'a', 'n', 'g', 'e', '\030', '\t', ' ', '\003', '(', '\013', '2', '.', '.', 'g', 'o', 'o', 'g', 'l', -'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', -'o', '.', 'R', 'e', 's', 'e', 'r', 'v', 'e', 'd', 'R', 'a', 'n', 'g', 'e', 'R', '\r', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', -'R', 'a', 'n', 'g', 'e', '\022', '#', '\n', '\r', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', '_', 'n', 'a', 'm', 'e', '\030', '\n', ' ', -'\003', '(', '\t', 'R', '\014', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', 'N', 'a', 'm', 'e', '\032', 'z', '\n', '\016', 'E', 'x', 't', 'e', -'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', 'e', '\022', '\024', '\n', '\005', 's', 't', 'a', 'r', 't', '\030', '\001', ' ', '\001', '(', '\005', -'R', '\005', 's', 't', 'a', 'r', 't', '\022', '\020', '\n', '\003', 'e', 'n', 'd', '\030', '\002', ' ', '\001', '(', '\005', 'R', '\003', 'e', 'n', 'd', -'\022', '@', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\003', ' ', '\001', '(', '\013', '2', '&', '.', 'g', 'o', 'o', 'g', 'l', -'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', 'e', -'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\032', '7', '\n', '\r', 'R', 'e', 's', 'e', 'r', -'v', 'e', 'd', 'R', 'a', 'n', 'g', 'e', '\022', '\024', '\n', '\005', 's', 't', 'a', 'r', 't', '\030', '\001', ' ', '\001', '(', '\005', 'R', '\005', -'s', 't', 'a', 'r', 't', '\022', '\020', '\n', '\003', 'e', 'n', 'd', '\030', '\002', ' ', '\001', '(', '\005', 'R', '\003', 'e', 'n', 'd', '\"', '|', -'\n', '\025', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', 'X', -'\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', -' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', -'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', -'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', '\"', -'\301', '\006', '\n', '\024', 'F', 'i', 'e', 'l', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '\022', -'\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\026', '\n', '\006', 'n', 'u', -'m', 'b', 'e', 'r', '\030', '\003', ' ', '\001', '(', '\005', 'R', '\006', 'n', 'u', 'm', 'b', 'e', 'r', '\022', 'A', '\n', '\005', 'l', 'a', 'b', -'e', 'l', '\030', '\004', ' ', '\001', '(', '\016', '2', '+', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', -'f', '.', 'F', 'i', 'e', 'l', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '.', 'L', 'a', -'b', 'e', 'l', 'R', '\005', 'l', 'a', 'b', 'e', 'l', '\022', '>', '\n', '\004', 't', 'y', 'p', 'e', '\030', '\005', ' ', '\001', '(', '\016', '2', -'*', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'D', 'e', -'s', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '.', 'T', 'y', 'p', 'e', 'R', '\004', 't', 'y', 'p', 'e', '\022', -'\033', '\n', '\t', 't', 'y', 'p', 'e', '_', 'n', 'a', 'm', 'e', '\030', '\006', ' ', '\001', '(', '\t', 'R', '\010', 't', 'y', 'p', 'e', 'N', -'a', 'm', 'e', '\022', '\032', '\n', '\010', 'e', 'x', 't', 'e', 'n', 'd', 'e', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\010', 'e', 'x', -'t', 'e', 'n', 'd', 'e', 'e', '\022', '#', '\n', '\r', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\007', -' ', '\001', '(', '\t', 'R', '\014', 'd', 'e', 'f', 'a', 'u', 'l', 't', 'V', 'a', 'l', 'u', 'e', '\022', '\037', '\n', '\013', 'o', 'n', 'e', -'o', 'f', '_', 'i', 'n', 'd', 'e', 'x', '\030', '\t', ' ', '\001', '(', '\005', 'R', '\n', 'o', 'n', 'e', 'o', 'f', 'I', 'n', 'd', 'e', -'x', '\022', '\033', '\n', '\t', 'j', 's', 'o', 'n', '_', 'n', 'a', 'm', 'e', '\030', '\n', ' ', '\001', '(', '\t', 'R', '\010', 'j', 's', 'o', -'n', 'N', 'a', 'm', 'e', '\022', '7', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\010', ' ', '\001', '(', '\013', '2', '\035', '.', -'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'O', 'p', 't', 'i', -'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\022', '\'', '\n', '\017', 'p', 'r', 'o', 't', 'o', '3', '_', 'o', 'p', -'t', 'i', 'o', 'n', 'a', 'l', '\030', '\021', ' ', '\001', '(', '\010', 'R', '\016', 'p', 'r', 'o', 't', 'o', '3', 'O', 'p', 't', 'i', 'o', -'n', 'a', 'l', '\"', '\266', '\002', '\n', '\004', 'T', 'y', 'p', 'e', '\022', '\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'D', 'O', 'U', 'B', -'L', 'E', '\020', '\001', '\022', '\016', '\n', '\n', 'T', 'Y', 'P', 'E', '_', 'F', 'L', 'O', 'A', 'T', '\020', '\002', '\022', '\016', '\n', '\n', 'T', -'Y', 'P', 'E', '_', 'I', 'N', 'T', '6', '4', '\020', '\003', '\022', '\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'U', 'I', 'N', 'T', '6', -'4', '\020', '\004', '\022', '\016', '\n', '\n', 'T', 'Y', 'P', 'E', '_', 'I', 'N', 'T', '3', '2', '\020', '\005', '\022', '\020', '\n', '\014', 'T', 'Y', -'P', 'E', '_', 'F', 'I', 'X', 'E', 'D', '6', '4', '\020', '\006', '\022', '\020', '\n', '\014', 'T', 'Y', 'P', 'E', '_', 'F', 'I', 'X', 'E', -'D', '3', '2', '\020', '\007', '\022', '\r', '\n', '\t', 'T', 'Y', 'P', 'E', '_', 'B', 'O', 'O', 'L', '\020', '\010', '\022', '\017', '\n', '\013', 'T', -'Y', 'P', 'E', '_', 'S', 'T', 'R', 'I', 'N', 'G', '\020', '\t', '\022', '\016', '\n', '\n', 'T', 'Y', 'P', 'E', '_', 'G', 'R', 'O', 'U', -'P', '\020', '\n', '\022', '\020', '\n', '\014', 'T', 'Y', 'P', 'E', '_', 'M', 'E', 'S', 'S', 'A', 'G', 'E', '\020', '\013', '\022', '\016', '\n', '\n', -'T', 'Y', 'P', 'E', '_', 'B', 'Y', 'T', 'E', 'S', '\020', '\014', '\022', '\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'U', 'I', 'N', 'T', -'3', '2', '\020', '\r', '\022', '\r', '\n', '\t', 'T', 'Y', 'P', 'E', '_', 'E', 'N', 'U', 'M', '\020', '\016', '\022', '\021', '\n', '\r', 'T', 'Y', -'P', 'E', '_', 'S', 'F', 'I', 'X', 'E', 'D', '3', '2', '\020', '\017', '\022', '\021', '\n', '\r', 'T', 'Y', 'P', 'E', '_', 'S', 'F', 'I', -'X', 'E', 'D', '6', '4', '\020', '\020', '\022', '\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'S', 'I', 'N', 'T', '3', '2', '\020', '\021', '\022', -'\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'S', 'I', 'N', 'T', '6', '4', '\020', '\022', '\"', 'C', '\n', '\005', 'L', 'a', 'b', 'e', 'l', -'\022', '\022', '\n', '\016', 'L', 'A', 'B', 'E', 'L', '_', 'O', 'P', 'T', 'I', 'O', 'N', 'A', 'L', '\020', '\001', '\022', '\022', '\n', '\016', 'L', -'A', 'B', 'E', 'L', '_', 'R', 'E', 'Q', 'U', 'I', 'R', 'E', 'D', '\020', '\002', '\022', '\022', '\n', '\016', 'L', 'A', 'B', 'E', 'L', '_', -'R', 'E', 'P', 'E', 'A', 'T', 'E', 'D', '\020', '\003', '\"', 'c', '\n', '\024', 'O', 'n', 'e', 'o', 'f', 'D', 'e', 's', 'c', 'r', 'i', -'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', -'n', 'a', 'm', 'e', '\022', '7', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\002', ' ', '\001', '(', '\013', '2', '\035', '.', 'g', -'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'O', 'n', 'e', 'o', 'f', 'O', 'p', 't', 'i', 'o', -'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\"', '\343', '\002', '\n', '\023', 'E', 'n', 'u', 'm', 'D', 'e', 's', 'c', 'r', -'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', -'\004', 'n', 'a', 'm', 'e', '\022', '?', '\n', '\005', 'v', 'a', 'l', 'u', 'e', '\030', '\002', ' ', '\003', '(', '\013', '2', ')', '.', 'g', 'o', -'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'E', 'n', 'u', 'm', 'V', 'a', 'l', 'u', 'e', 'D', 'e', -'s', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\005', 'v', 'a', 'l', 'u', 'e', '\022', '6', '\n', '\007', 'o', -'p', 't', 'i', 'o', 'n', 's', '\030', '\003', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', -'t', 'o', 'b', 'u', 'f', '.', 'E', 'n', 'u', 'm', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', -'s', '\022', ']', '\n', '\016', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', '_', 'r', 'a', 'n', 'g', 'e', '\030', '\004', ' ', '\003', '(', '\013', -'2', '6', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'E', 'n', 'u', 'm', 'D', 'e', -'s', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '.', 'E', 'n', 'u', 'm', 'R', 'e', 's', 'e', 'r', 'v', 'e', -'d', 'R', 'a', 'n', 'g', 'e', 'R', '\r', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', 'R', 'a', 'n', 'g', 'e', '\022', '#', '\n', '\r', -'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', '_', 'n', 'a', 'm', 'e', '\030', '\005', ' ', '\003', '(', '\t', 'R', '\014', 'r', 'e', 's', 'e', -'r', 'v', 'e', 'd', 'N', 'a', 'm', 'e', '\032', ';', '\n', '\021', 'E', 'n', 'u', 'm', 'R', 'e', 's', 'e', 'r', 'v', 'e', 'd', 'R', -'a', 'n', 'g', 'e', '\022', '\024', '\n', '\005', 's', 't', 'a', 'r', 't', '\030', '\001', ' ', '\001', '(', '\005', 'R', '\005', 's', 't', 'a', 'r', -'t', '\022', '\020', '\n', '\003', 'e', 'n', 'd', '\030', '\002', ' ', '\001', '(', '\005', 'R', '\003', 'e', 'n', 'd', '\"', '\203', '\001', '\n', '\030', 'E', -'n', 'u', 'm', 'V', 'a', 'l', 'u', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '\022', '\022', -'\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\026', '\n', '\006', 'n', 'u', 'm', -'b', 'e', 'r', '\030', '\002', ' ', '\001', '(', '\005', 'R', '\006', 'n', 'u', 'm', 'b', 'e', 'r', '\022', ';', '\n', '\007', 'o', 'p', 't', 'i', -'o', 'n', 's', '\030', '\003', ' ', '\001', '(', '\013', '2', '!', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', -'u', 'f', '.', 'E', 'n', 'u', 'm', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', -'o', 'n', 's', '\"', '\247', '\001', '\n', '\026', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', -'P', 'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', -'\022', '>', '\n', '\006', 'm', 'e', 't', 'h', 'o', 'd', '\030', '\002', ' ', '\003', '(', '\013', '2', '&', '.', 'g', 'o', 'o', 'g', 'l', 'e', -'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'M', 'e', 't', 'h', 'o', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', -'r', 'P', 'r', 'o', 't', 'o', 'R', '\006', 'm', 'e', 't', 'h', 'o', 'd', '\022', '9', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', -'\030', '\003', ' ', '\001', '(', '\013', '2', '\037', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', -'S', 'e', 'r', 'v', 'i', 'c', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\"', '\211', -'\002', '\n', '\025', 'M', 'e', 't', 'h', 'o', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '\022', -'\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\035', '\n', '\n', 'i', 'n', -'p', 'u', 't', '_', 't', 'y', 'p', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\t', 'i', 'n', 'p', 'u', 't', 'T', 'y', 'p', 'e', -'\022', '\037', '\n', '\013', 'o', 'u', 't', 'p', 'u', 't', '_', 't', 'y', 'p', 'e', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\n', 'o', 'u', -'t', 'p', 'u', 't', 'T', 'y', 'p', 'e', '\022', '8', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\004', ' ', '\001', '(', '\013', -'2', '\036', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'M', 'e', 't', 'h', 'o', 'd', -'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\022', '0', '\n', '\020', 'c', 'l', 'i', 'e', 'n', -'t', '_', 's', 't', 'r', 'e', 'a', 'm', 'i', 'n', 'g', '\030', '\005', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', -'\017', 'c', 'l', 'i', 'e', 'n', 't', 'S', 't', 'r', 'e', 'a', 'm', 'i', 'n', 'g', '\022', '0', '\n', '\020', 's', 'e', 'r', 'v', 'e', -'r', '_', 's', 't', 'r', 'e', 'a', 'm', 'i', 'n', 'g', '\030', '\006', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', -'\017', 's', 'e', 'r', 'v', 'e', 'r', 'S', 't', 'r', 'e', 'a', 'm', 'i', 'n', 'g', '\"', '\221', '\t', '\n', '\013', 'F', 'i', 'l', 'e', -'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '!', '\n', '\014', 'j', 'a', 'v', 'a', '_', 'p', 'a', 'c', 'k', 'a', 'g', 'e', '\030', '\001', -' ', '\001', '(', '\t', 'R', '\013', 'j', 'a', 'v', 'a', 'P', 'a', 'c', 'k', 'a', 'g', 'e', '\022', '0', '\n', '\024', 'j', 'a', 'v', 'a', -'_', 'o', 'u', 't', 'e', 'r', '_', 'c', 'l', 'a', 's', 's', 'n', 'a', 'm', 'e', '\030', '\010', ' ', '\001', '(', '\t', 'R', '\022', 'j', -'a', 'v', 'a', 'O', 'u', 't', 'e', 'r', 'C', 'l', 'a', 's', 's', 'n', 'a', 'm', 'e', '\022', '5', '\n', '\023', 'j', 'a', 'v', 'a', -'_', 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', '_', 'f', 'i', 'l', 'e', 's', '\030', '\n', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', -'l', 's', 'e', 'R', '\021', 'j', 'a', 'v', 'a', 'M', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'F', 'i', 'l', 'e', 's', '\022', 'D', '\n', -'\035', 'j', 'a', 'v', 'a', '_', 'g', 'e', 'n', 'e', 'r', 'a', 't', 'e', '_', 'e', 'q', 'u', 'a', 'l', 's', '_', 'a', 'n', 'd', -'_', 'h', 'a', 's', 'h', '\030', '\024', ' ', '\001', '(', '\010', 'B', '\002', '\030', '\001', 'R', '\031', 'j', 'a', 'v', 'a', 'G', 'e', 'n', 'e', -'r', 'a', 't', 'e', 'E', 'q', 'u', 'a', 'l', 's', 'A', 'n', 'd', 'H', 'a', 's', 'h', '\022', ':', '\n', '\026', 'j', 'a', 'v', 'a', -'_', 's', 't', 'r', 'i', 'n', 'g', '_', 'c', 'h', 'e', 'c', 'k', '_', 'u', 't', 'f', '8', '\030', '\033', ' ', '\001', '(', '\010', ':', -'\005', 'f', 'a', 'l', 's', 'e', 'R', '\023', 'j', 'a', 'v', 'a', 'S', 't', 'r', 'i', 'n', 'g', 'C', 'h', 'e', 'c', 'k', 'U', 't', -'f', '8', '\022', 'S', '\n', '\014', 'o', 'p', 't', 'i', 'm', 'i', 'z', 'e', '_', 'f', 'o', 'r', '\030', '\t', ' ', '\001', '(', '\016', '2', -')', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'l', 'e', 'O', 'p', 't', -'i', 'o', 'n', 's', '.', 'O', 'p', 't', 'i', 'm', 'i', 'z', 'e', 'M', 'o', 'd', 'e', ':', '\005', 'S', 'P', 'E', 'E', 'D', 'R', -'\013', 'o', 'p', 't', 'i', 'm', 'i', 'z', 'e', 'F', 'o', 'r', '\022', '\035', '\n', '\n', 'g', 'o', '_', 'p', 'a', 'c', 'k', 'a', 'g', -'e', '\030', '\013', ' ', '\001', '(', '\t', 'R', '\t', 'g', 'o', 'P', 'a', 'c', 'k', 'a', 'g', 'e', '\022', '5', '\n', '\023', 'c', 'c', '_', -'g', 'e', 'n', 'e', 'r', 'i', 'c', '_', 's', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\030', '\020', ' ', '\001', '(', '\010', ':', '\005', 'f', -'a', 'l', 's', 'e', 'R', '\021', 'c', 'c', 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\022', '9', -'\n', '\025', 'j', 'a', 'v', 'a', '_', 'g', 'e', 'n', 'e', 'r', 'i', 'c', '_', 's', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\030', '\021', -' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\023', 'j', 'a', 'v', 'a', 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'S', -'e', 'r', 'v', 'i', 'c', 'e', 's', '\022', '5', '\n', '\023', 'p', 'y', '_', 'g', 'e', 'n', 'e', 'r', 'i', 'c', '_', 's', 'e', 'r', -'v', 'i', 'c', 'e', 's', '\030', '\022', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\021', 'p', 'y', 'G', 'e', 'n', -'e', 'r', 'i', 'c', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\022', '7', '\n', '\024', 'p', 'h', 'p', '_', 'g', 'e', 'n', 'e', 'r', -'i', 'c', '_', 's', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\030', '*', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', -'\022', 'p', 'h', 'p', 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\022', '%', '\n', '\n', 'd', 'e', -'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '\027', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\n', 'd', 'e', -'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', '.', '\n', '\020', 'c', 'c', '_', 'e', 'n', 'a', 'b', 'l', 'e', '_', 'a', 'r', 'e', -'n', 'a', 's', '\030', '\037', ' ', '\001', '(', '\010', ':', '\004', 't', 'r', 'u', 'e', 'R', '\016', 'c', 'c', 'E', 'n', 'a', 'b', 'l', 'e', -'A', 'r', 'e', 'n', 'a', 's', '\022', '*', '\n', '\021', 'o', 'b', 'j', 'c', '_', 'c', 'l', 'a', 's', 's', '_', 'p', 'r', 'e', 'f', -'i', 'x', '\030', '$', ' ', '\001', '(', '\t', 'R', '\017', 'o', 'b', 'j', 'c', 'C', 'l', 'a', 's', 's', 'P', 'r', 'e', 'f', 'i', 'x', -'\022', ')', '\n', '\020', 'c', 's', 'h', 'a', 'r', 'p', '_', 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\030', '%', ' ', '\001', '(', -'\t', 'R', '\017', 'c', 's', 'h', 'a', 'r', 'p', 'N', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\022', '!', '\n', '\014', 's', 'w', 'i', -'f', 't', '_', 'p', 'r', 'e', 'f', 'i', 'x', '\030', '\'', ' ', '\001', '(', '\t', 'R', '\013', 's', 'w', 'i', 'f', 't', 'P', 'r', 'e', -'f', 'i', 'x', '\022', '(', '\n', '\020', 'p', 'h', 'p', '_', 'c', 'l', 'a', 's', 's', '_', 'p', 'r', 'e', 'f', 'i', 'x', '\030', '(', -' ', '\001', '(', '\t', 'R', '\016', 'p', 'h', 'p', 'C', 'l', 'a', 's', 's', 'P', 'r', 'e', 'f', 'i', 'x', '\022', '#', '\n', '\r', 'p', -'h', 'p', '_', 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\030', ')', ' ', '\001', '(', '\t', 'R', '\014', 'p', 'h', 'p', 'N', 'a', -'m', 'e', 's', 'p', 'a', 'c', 'e', '\022', '4', '\n', '\026', 'p', 'h', 'p', '_', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '_', 'n', -'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\030', ',', ' ', '\001', '(', '\t', 'R', '\024', 'p', 'h', 'p', 'M', 'e', 't', 'a', 'd', 'a', -'t', 'a', 'N', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\022', '!', '\n', '\014', 'r', 'u', 'b', 'y', '_', 'p', 'a', 'c', 'k', 'a', -'g', 'e', '\030', '-', ' ', '\001', '(', '\t', 'R', '\013', 'r', 'u', 'b', 'y', 'P', 'a', 'c', 'k', 'a', 'g', 'e', '\022', 'X', '\n', '\024', -'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', -'(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', -'t', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', -'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '\"', ':', '\n', '\014', 'O', 'p', 't', 'i', 'm', 'i', 'z', 'e', 'M', 'o', -'d', 'e', '\022', '\t', '\n', '\005', 'S', 'P', 'E', 'E', 'D', '\020', '\001', '\022', '\r', '\n', '\t', 'C', 'O', 'D', 'E', '_', 'S', 'I', 'Z', -'E', '\020', '\002', '\022', '\020', '\n', '\014', 'L', 'I', 'T', 'E', '_', 'R', 'U', 'N', 'T', 'I', 'M', 'E', '\020', '\003', '*', '\t', '\010', '\350', -'\007', '\020', '\200', '\200', '\200', '\200', '\002', 'J', '\004', '\010', '&', '\020', '\'', '\"', '\343', '\002', '\n', '\016', 'M', 'e', 's', 's', 'a', 'g', 'e', -'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '<', '\n', '\027', 'm', 'e', 's', 's', 'a', 'g', 'e', '_', 's', 'e', 't', '_', 'w', 'i', -'r', 'e', '_', 'f', 'o', 'r', 'm', 'a', 't', '\030', '\001', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\024', 'm', -'e', 's', 's', 'a', 'g', 'e', 'S', 'e', 't', 'W', 'i', 'r', 'e', 'F', 'o', 'r', 'm', 'a', 't', '\022', 'L', '\n', '\037', 'n', 'o', -'_', 's', 't', 'a', 'n', 'd', 'a', 'r', 'd', '_', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '_', 'a', 'c', 'c', 'e', -'s', 's', 'o', 'r', '\030', '\002', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\034', 'n', 'o', 'S', 't', 'a', 'n', -'d', 'a', 'r', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'A', 'c', 'c', 'e', 's', 's', 'o', 'r', '\022', '%', '\n', -'\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '\003', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', -'\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', '\033', '\n', '\t', 'm', 'a', 'p', '_', 'e', 'n', 't', 'r', 'y', '\030', -'\007', ' ', '\001', '(', '\010', 'R', '\010', 'm', 'a', 'p', 'E', 'n', 't', 'r', 'y', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', -'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', -'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', -'t', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', -'p', 't', 'i', 'o', 'n', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', 'J', '\004', '\010', '\004', '\020', '\005', 'J', '\004', '\010', -'\005', '\020', '\006', 'J', '\004', '\010', '\006', '\020', '\007', 'J', '\004', '\010', '\010', '\020', '\t', 'J', '\004', '\010', '\t', '\020', '\n', '\"', '\222', '\004', '\n', -'\014', 'F', 'i', 'e', 'l', 'd', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', 'A', '\n', '\005', 'c', 't', 'y', 'p', 'e', '\030', '\001', ' ', -'\001', '(', '\016', '2', '#', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', -'l', 'd', 'O', 'p', 't', 'i', 'o', 'n', 's', '.', 'C', 'T', 'y', 'p', 'e', ':', '\006', 'S', 'T', 'R', 'I', 'N', 'G', 'R', '\005', -'c', 't', 'y', 'p', 'e', '\022', '\026', '\n', '\006', 'p', 'a', 'c', 'k', 'e', 'd', '\030', '\002', ' ', '\001', '(', '\010', 'R', '\006', 'p', 'a', -'c', 'k', 'e', 'd', '\022', 'G', '\n', '\006', 'j', 's', 't', 'y', 'p', 'e', '\030', '\006', ' ', '\001', '(', '\016', '2', '$', '.', 'g', 'o', -'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'O', 'p', 't', 'i', 'o', 'n', -'s', '.', 'J', 'S', 'T', 'y', 'p', 'e', ':', '\t', 'J', 'S', '_', 'N', 'O', 'R', 'M', 'A', 'L', 'R', '\006', 'j', 's', 't', 'y', -'p', 'e', '\022', '\031', '\n', '\004', 'l', 'a', 'z', 'y', '\030', '\005', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\004', -'l', 'a', 'z', 'y', '\022', '.', '\n', '\017', 'u', 'n', 'v', 'e', 'r', 'i', 'f', 'i', 'e', 'd', '_', 'l', 'a', 'z', 'y', '\030', '\017', -' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\016', 'u', 'n', 'v', 'e', 'r', 'i', 'f', 'i', 'e', 'd', 'L', 'a', -'z', 'y', '\022', '%', '\n', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '\003', ' ', '\001', '(', '\010', ':', '\005', 'f', -'a', 'l', 's', 'e', 'R', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', '\031', '\n', '\004', 'w', 'e', 'a', 'k', '\030', -'\n', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\004', 'w', 'e', 'a', 'k', '\022', 'X', '\n', '\024', 'u', 'n', 'i', -'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', -'$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', -'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', -'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '\"', '/', '\n', '\005', 'C', 'T', 'y', 'p', 'e', '\022', '\n', '\n', '\006', 'S', 'T', 'R', 'I', -'N', 'G', '\020', '\000', '\022', '\010', '\n', '\004', 'C', 'O', 'R', 'D', '\020', '\001', '\022', '\020', '\n', '\014', 'S', 'T', 'R', 'I', 'N', 'G', '_', -'P', 'I', 'E', 'C', 'E', '\020', '\002', '\"', '5', '\n', '\006', 'J', 'S', 'T', 'y', 'p', 'e', '\022', '\r', '\n', '\t', 'J', 'S', '_', 'N', -'O', 'R', 'M', 'A', 'L', '\020', '\000', '\022', '\r', '\n', '\t', 'J', 'S', '_', 'S', 'T', 'R', 'I', 'N', 'G', '\020', '\001', '\022', '\r', '\n', -'\t', 'J', 'S', '_', 'N', 'U', 'M', 'B', 'E', 'R', '\020', '\002', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', 'J', '\004', -'\010', '\004', '\020', '\005', '\"', 's', '\n', '\014', 'O', 'n', 'e', 'o', 'f', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', 'X', '\n', '\024', 'u', -'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', -'\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', -'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', -'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', '\"', '\300', '\001', '\n', -'\013', 'E', 'n', 'u', 'm', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '\037', '\n', '\013', 'a', 'l', 'l', 'o', 'w', '_', 'a', 'l', 'i', -'a', 's', '\030', '\002', ' ', '\001', '(', '\010', 'R', '\n', 'a', 'l', 'l', 'o', 'w', 'A', 'l', 'i', 'a', 's', '\022', '%', '\n', '\n', 'd', -'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '\003', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\n', 'd', -'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', -'d', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', -'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', -'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '*', -'\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', 'J', '\004', '\010', '\005', '\020', '\006', '\"', '\236', '\001', '\n', '\020', 'E', 'n', 'u', 'm', -'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '%', '\n', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', -'d', '\030', '\001', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', -'d', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', -'\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', -'.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', -'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', -'\200', '\002', '\"', '\234', '\001', '\n', '\016', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '%', '\n', '\n', -'d', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '!', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\n', -'d', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', -'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', -'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', -'t', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', -'*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', '\"', '\340', '\002', '\n', '\r', 'M', 'e', 't', 'h', 'o', 'd', 'O', 'p', 't', -'i', 'o', 'n', 's', '\022', '%', '\n', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '!', ' ', '\001', '(', '\010', ':', -'\005', 'f', 'a', 'l', 's', 'e', 'R', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', 'q', '\n', '\021', 'i', 'd', 'e', -'m', 'p', 'o', 't', 'e', 'n', 'c', 'y', '_', 'l', 'e', 'v', 'e', 'l', '\030', '\"', ' ', '\001', '(', '\016', '2', '/', '.', 'g', 'o', -'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'M', 'e', 't', 'h', 'o', 'd', 'O', 'p', 't', 'i', 'o', -'n', 's', '.', 'I', 'd', 'e', 'm', 'p', 'o', 't', 'e', 'n', 'c', 'y', 'L', 'e', 'v', 'e', 'l', ':', '\023', 'I', 'D', 'E', 'M', -'P', 'O', 'T', 'E', 'N', 'C', 'Y', '_', 'U', 'N', 'K', 'N', 'O', 'W', 'N', 'R', '\020', 'i', 'd', 'e', 'm', 'p', 'o', 't', 'e', -'n', 'c', 'y', 'L', 'e', 'v', 'e', 'l', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', -'_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', -'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', -'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '\"', 'P', -'\n', '\020', 'I', 'd', 'e', 'm', 'p', 'o', 't', 'e', 'n', 'c', 'y', 'L', 'e', 'v', 'e', 'l', '\022', '\027', '\n', '\023', 'I', 'D', 'E', -'M', 'P', 'O', 'T', 'E', 'N', 'C', 'Y', '_', 'U', 'N', 'K', 'N', 'O', 'W', 'N', '\020', '\000', '\022', '\023', '\n', '\017', 'N', 'O', '_', -'S', 'I', 'D', 'E', '_', 'E', 'F', 'F', 'E', 'C', 'T', 'S', '\020', '\001', '\022', '\016', '\n', '\n', 'I', 'D', 'E', 'M', 'P', 'O', 'T', -'E', 'N', 'T', '\020', '\002', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', '\"', '\232', '\003', '\n', '\023', 'U', 'n', 'i', 'n', -'t', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '\022', 'A', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\002', -' ', '\003', '(', '\013', '2', '-', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', -'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '.', 'N', 'a', 'm', 'e', 'P', 'a', 'r', -'t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', ')', '\n', '\020', 'i', 'd', 'e', 'n', 't', 'i', 'f', 'i', 'e', 'r', '_', 'v', 'a', 'l', -'u', 'e', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\017', 'i', 'd', 'e', 'n', 't', 'i', 'f', 'i', 'e', 'r', 'V', 'a', 'l', 'u', 'e', -'\022', ',', '\n', '\022', 'p', 'o', 's', 'i', 't', 'i', 'v', 'e', '_', 'i', 'n', 't', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\004', ' ', -'\001', '(', '\004', 'R', '\020', 'p', 'o', 's', 'i', 't', 'i', 'v', 'e', 'I', 'n', 't', 'V', 'a', 'l', 'u', 'e', '\022', ',', '\n', '\022', -'n', 'e', 'g', 'a', 't', 'i', 'v', 'e', '_', 'i', 'n', 't', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\005', ' ', '\001', '(', '\003', 'R', -'\020', 'n', 'e', 'g', 'a', 't', 'i', 'v', 'e', 'I', 'n', 't', 'V', 'a', 'l', 'u', 'e', '\022', '!', '\n', '\014', 'd', 'o', 'u', 'b', -'l', 'e', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\006', ' ', '\001', '(', '\001', 'R', '\013', 'd', 'o', 'u', 'b', 'l', 'e', 'V', 'a', 'l', -'u', 'e', '\022', '!', '\n', '\014', 's', 't', 'r', 'i', 'n', 'g', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\007', ' ', '\001', '(', '\014', 'R', -'\013', 's', 't', 'r', 'i', 'n', 'g', 'V', 'a', 'l', 'u', 'e', '\022', '\'', '\n', '\017', 'a', 'g', 'g', 'r', 'e', 'g', 'a', 't', 'e', -'_', 'v', 'a', 'l', 'u', 'e', '\030', '\010', ' ', '\001', '(', '\t', 'R', '\016', 'a', 'g', 'g', 'r', 'e', 'g', 'a', 't', 'e', 'V', 'a', -'l', 'u', 'e', '\032', 'J', '\n', '\010', 'N', 'a', 'm', 'e', 'P', 'a', 'r', 't', '\022', '\033', '\n', '\t', 'n', 'a', 'm', 'e', '_', 'p', -'a', 'r', 't', '\030', '\001', ' ', '\002', '(', '\t', 'R', '\010', 'n', 'a', 'm', 'e', 'P', 'a', 'r', 't', '\022', '!', '\n', '\014', 'i', 's', -'_', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\030', '\002', ' ', '\002', '(', '\010', 'R', '\013', 'i', 's', 'E', 'x', 't', 'e', 'n', -'s', 'i', 'o', 'n', '\"', '\247', '\002', '\n', '\016', 'S', 'o', 'u', 'r', 'c', 'e', 'C', 'o', 'd', 'e', 'I', 'n', 'f', 'o', '\022', 'D', -'\n', '\010', 'l', 'o', 'c', 'a', 't', 'i', 'o', 'n', '\030', '\001', ' ', '\003', '(', '\013', '2', '(', '.', 'g', 'o', 'o', 'g', 'l', 'e', -'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 'o', 'u', 'r', 'c', 'e', 'C', 'o', 'd', 'e', 'I', 'n', 'f', 'o', '.', -'L', 'o', 'c', 'a', 't', 'i', 'o', 'n', 'R', '\010', 'l', 'o', 'c', 'a', 't', 'i', 'o', 'n', '\032', '\316', '\001', '\n', '\010', 'L', 'o', -'c', 'a', 't', 'i', 'o', 'n', '\022', '\026', '\n', '\004', 'p', 'a', 't', 'h', '\030', '\001', ' ', '\003', '(', '\005', 'B', '\002', '\020', '\001', 'R', -'\004', 'p', 'a', 't', 'h', '\022', '\026', '\n', '\004', 's', 'p', 'a', 'n', '\030', '\002', ' ', '\003', '(', '\005', 'B', '\002', '\020', '\001', 'R', '\004', -'s', 'p', 'a', 'n', '\022', ')', '\n', '\020', 'l', 'e', 'a', 'd', 'i', 'n', 'g', '_', 'c', 'o', 'm', 'm', 'e', 'n', 't', 's', '\030', -'\003', ' ', '\001', '(', '\t', 'R', '\017', 'l', 'e', 'a', 'd', 'i', 'n', 'g', 'C', 'o', 'm', 'm', 'e', 'n', 't', 's', '\022', '+', '\n', -'\021', 't', 'r', 'a', 'i', 'l', 'i', 'n', 'g', '_', 'c', 'o', 'm', 'm', 'e', 'n', 't', 's', '\030', '\004', ' ', '\001', '(', '\t', 'R', -'\020', 't', 'r', 'a', 'i', 'l', 'i', 'n', 'g', 'C', 'o', 'm', 'm', 'e', 'n', 't', 's', '\022', ':', '\n', '\031', 'l', 'e', 'a', 'd', -'i', 'n', 'g', '_', 'd', 'e', 't', 'a', 'c', 'h', 'e', 'd', '_', 'c', 'o', 'm', 'm', 'e', 'n', 't', 's', '\030', '\006', ' ', '\003', -'(', '\t', 'R', '\027', 'l', 'e', 'a', 'd', 'i', 'n', 'g', 'D', 'e', 't', 'a', 'c', 'h', 'e', 'd', 'C', 'o', 'm', 'm', 'e', 'n', -'t', 's', '\"', '\321', '\001', '\n', '\021', 'G', 'e', 'n', 'e', 'r', 'a', 't', 'e', 'd', 'C', 'o', 'd', 'e', 'I', 'n', 'f', 'o', '\022', -'M', '\n', '\n', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', '\030', '\001', ' ', '\003', '(', '\013', '2', '-', '.', 'g', 'o', 'o', -'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'G', 'e', 'n', 'e', 'r', 'a', 't', 'e', 'd', 'C', 'o', 'd', -'e', 'I', 'n', 'f', 'o', '.', 'A', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 'R', '\n', 'a', 'n', 'n', 'o', 't', 'a', 't', -'i', 'o', 'n', '\032', 'm', '\n', '\n', 'A', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', '\022', '\026', '\n', '\004', 'p', 'a', 't', 'h', -'\030', '\001', ' ', '\003', '(', '\005', 'B', '\002', '\020', '\001', 'R', '\004', 'p', 'a', 't', 'h', '\022', '\037', '\n', '\013', 's', 'o', 'u', 'r', 'c', -'e', '_', 'f', 'i', 'l', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\n', 's', 'o', 'u', 'r', 'c', 'e', 'F', 'i', 'l', 'e', '\022', -'\024', '\n', '\005', 'b', 'e', 'g', 'i', 'n', '\030', '\003', ' ', '\001', '(', '\005', 'R', '\005', 'b', 'e', 'g', 'i', 'n', '\022', '\020', '\n', '\003', -'e', 'n', 'd', '\030', '\004', ' ', '\001', '(', '\005', 'R', '\003', 'e', 'n', 'd', 'B', '~', '\n', '\023', 'c', 'o', 'm', '.', 'g', 'o', 'o', -'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', 'B', '\020', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', -'r', 'o', 't', 'o', 's', 'H', '\001', 'Z', '-', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'g', 'o', 'l', 'a', 'n', 'g', '.', 'o', 'r', -'g', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 't', 'y', 'p', 'e', 's', '/', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', -'o', 'r', 'p', 'b', '\370', '\001', '\001', '\242', '\002', '\003', 'G', 'P', 'B', '\252', '\002', '\032', 'G', 'o', 'o', 'g', 'l', 'e', '.', 'P', 'r', -'o', 't', 'o', 'b', 'u', 'f', '.', 'R', 'e', 'f', 'l', 'e', 'c', 't', 'i', 'o', 'n', -}; +const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( + const upb_EnumValueDef* v) { + return v->opts; +} -static _upb_DefPool_Init *deps[1] = { - NULL -}; +bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* v) { + return v->opts != (void*)kUpbDefOptDefault; +} -_upb_DefPool_Init google_protobuf_descriptor_proto_upbdefinit = { - deps, - &google_protobuf_descriptor_proto_upb_file_layout, - "google/protobuf/descriptor.proto", - UPB_STRINGVIEW_INIT(descriptor, 7667) -}; +const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* v) { + return v->parent; +} -/** upb/def.c ************************************************************/ +const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* v) { + return v->full_name; +} -#include -#include -#include -#include -#include +const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v) { + return _upb_DefBuilder_FullToShort(v->full_name); +} +int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v) { return v->number; } -/* Must be last. */ +uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v) { + // Compute index in our parent's array. + return v - upb_EnumDef_Value(v->parent, 0); +} -typedef struct { - size_t len; - char str[1]; /* Null-terminated string data follows. */ -} str_t; +static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_EnumValueDescriptorProto* val_proto, + upb_EnumDef* e, upb_EnumValueDef* v) { + upb_StringView name = google_protobuf_EnumValueDescriptorProto_name(val_proto); -/* The upb core does not generally have a concept of default instances. However - * for descriptor options we make an exception since the max size is known and - * modest (<200 bytes). All types can share a default instance since it is - * initialized to zeroes. - * - * We have to allocate an extra pointer for upb's internal metadata. */ -static const char opt_default_buf[_UPB_MAXOPT_SIZE + sizeof(void*)] = {0}; -static const char* opt_default = &opt_default_buf[sizeof(void*)]; + v->parent = e; // Must happen prior to _upb_DefBuilder_Add() + v->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + v->number = google_protobuf_EnumValueDescriptorProto_number(val_proto); + _upb_DefBuilder_Add(ctx, v->full_name, + _upb_DefType_Pack(v, UPB_DEFTYPE_ENUMVAL)); -struct upb_FieldDef { - const google_protobuf_FieldOptions* opts; - const upb_FileDef* file; - const upb_MessageDef* msgdef; - const char* full_name; - const char* json_name; - union { - int64_t sint; - uint64_t uint; - double dbl; - float flt; - bool boolean; - str_t* str; - } defaultval; - union { - const upb_OneofDef* oneof; - const upb_MessageDef* extension_scope; - } scope; - union { - const upb_MessageDef* msgdef; - const upb_EnumDef* enumdef; - const google_protobuf_FieldDescriptorProto* unresolved; - } sub; - uint32_t number_; - uint16_t index_; - uint16_t layout_index; /* Index into msgdef->layout->fields or file->exts */ - bool has_default; - bool is_extension_; - bool packed_; - bool proto3_optional_; - bool has_json_name_; - upb_FieldType type_; - upb_Label label_; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif -}; + UBP_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions, + val_proto); -struct upb_ExtensionRange { - const google_protobuf_ExtensionRangeOptions* opts; - int32_t start; - int32_t end; -}; + bool ok = _upb_EnumDef_Insert(e, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} -struct upb_MessageDef { - const google_protobuf_MessageOptions* opts; - const upb_MiniTable* layout; - const upb_FileDef* file; - const upb_MessageDef* containing_type; - const char* full_name; +// Allocate and initialize an array of |n| enum value defs owned by |e|. +upb_EnumValueDef* _upb_EnumValueDefs_New( + upb_DefBuilder* ctx, const char* prefix, int n, + const google_protobuf_EnumValueDescriptorProto* const* protos, upb_EnumDef* e, + bool* is_sorted) { + _upb_DefType_CheckPadding(sizeof(upb_EnumValueDef)); - /* Tables for looking up fields by number and name. */ - upb_inttable itof; - upb_strtable ntof; + upb_EnumValueDef* v = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumValueDef) * n); - /* All nested defs. - * MEM: We could save some space here by putting nested defs in a contiguous - * region and calculating counts from offsets or vice-versa. */ - const upb_FieldDef* fields; - const upb_OneofDef* oneofs; - const upb_ExtensionRange* ext_ranges; - const upb_MessageDef* nested_msgs; - const upb_EnumDef* nested_enums; - const upb_FieldDef* nested_exts; - int field_count; - int real_oneof_count; - int oneof_count; - int ext_range_count; - int nested_msg_count; - int nested_enum_count; - int nested_ext_count; - bool in_message_set; - upb_WellKnown well_known_type; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif -}; + *is_sorted = true; + uint32_t previous = 0; + for (size_t i = 0; i < n; i++) { + create_enumvaldef(ctx, prefix, protos[i], e, &v[i]); -struct upb_EnumDef { - const google_protobuf_EnumOptions* opts; - const upb_MiniTable_Enum* layout; // Only for proto2. - const upb_FileDef* file; - const upb_MessageDef* containing_type; // Could be merged with "file". - const char* full_name; - upb_strtable ntoi; - upb_inttable iton; - const upb_EnumValueDef* values; - int value_count; - int32_t defaultval; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif -}; + const uint32_t current = v[i].number; + if (previous > current) *is_sorted = false; + previous = current; + } -struct upb_EnumValueDef { - const google_protobuf_EnumValueOptions* opts; - const upb_EnumDef* parent; - const char* full_name; - int32_t number; -}; + if (upb_FileDef_Syntax(ctx->file) == kUpb_Syntax_Proto3 && n > 0 && + v[0].number != 0) { + _upb_DefBuilder_Errf(ctx, + "for proto3, the first enum value must be zero (%s)", + upb_EnumDef_FullName(e)); + } -struct upb_OneofDef { - const google_protobuf_OneofOptions* opts; - const upb_MessageDef* parent; - const char* full_name; - int field_count; - bool synthetic; - const upb_FieldDef** fields; - upb_strtable ntof; - upb_inttable itof; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif -}; + return v; +} -struct upb_FileDef { - const google_protobuf_FileOptions* opts; - const char* name; - const char* package; - const upb_FileDef** deps; - const int32_t* public_deps; - const int32_t* weak_deps; - const upb_MessageDef* top_lvl_msgs; - const upb_EnumDef* top_lvl_enums; - const upb_FieldDef* top_lvl_exts; - const upb_ServiceDef* services; - const upb_MiniTable_Extension** ext_layouts; - const upb_DefPool* symtab; - int dep_count; - int public_dep_count; - int weak_dep_count; - int top_lvl_msg_count; - int top_lvl_enum_count; - int top_lvl_ext_count; - int service_count; - int ext_count; /* All exts in the file. */ - upb_Syntax syntax; -}; +// Must be last. -struct upb_MethodDef { - const google_protobuf_MethodOptions* opts; - upb_ServiceDef* service; - const char* full_name; - const upb_MessageDef* input_type; - const upb_MessageDef* output_type; - int index; - bool client_streaming; - bool server_streaming; +struct upb_ExtensionRange { + const google_protobuf_ExtensionRangeOptions* opts; + int32_t start; + int32_t end; }; -struct upb_ServiceDef { - const google_protobuf_ServiceOptions* opts; - const upb_FileDef* file; - const char* full_name; - upb_MethodDef* methods; - int method_count; - int index; -}; +upb_ExtensionRange* _upb_ExtensionRange_At(const upb_ExtensionRange* r, int i) { + return (upb_ExtensionRange*)&r[i]; +} + +const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( + const upb_ExtensionRange* r) { + return r->opts; +} + +bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r) { + return r->opts != (void*)kUpbDefOptDefault; +} -struct upb_DefPool { - upb_Arena* arena; - upb_strtable syms; /* full_name -> packed def ptr */ - upb_strtable files; /* file_name -> upb_FileDef* */ - upb_inttable exts; /* upb_MiniTable_Extension* -> upb_FieldDef* */ - upb_ExtensionRegistry* extreg; - size_t bytes_loaded; -}; +int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* r) { + return r->start; +} -/* Inside a symtab we store tagged pointers to specific def types. */ -typedef enum { - UPB_DEFTYPE_MASK = 7, +int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r) { return r->end; } - /* Only inside symtab table. */ - UPB_DEFTYPE_EXT = 0, - UPB_DEFTYPE_MSG = 1, - UPB_DEFTYPE_ENUM = 2, - UPB_DEFTYPE_ENUMVAL = 3, - UPB_DEFTYPE_SERVICE = 4, +upb_ExtensionRange* _upb_ExtensionRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_DescriptorProto_ExtensionRange* const* protos, + const upb_MessageDef* m) { + upb_ExtensionRange* r = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_ExtensionRange) * n); - /* Only inside message table. */ - UPB_DEFTYPE_FIELD = 0, - UPB_DEFTYPE_ONEOF = 1, - UPB_DEFTYPE_FIELD_JSONNAME = 2, + for (int i = 0; i < n; i++) { + const int32_t start = + google_protobuf_DescriptorProto_ExtensionRange_start(protos[i]); + const int32_t end = google_protobuf_DescriptorProto_ExtensionRange_end(protos[i]); + const int32_t max = + google_protobuf_MessageOptions_message_set_wire_format(upb_MessageDef_Options(m)) + ? INT32_MAX + : kUpb_MaxFieldNumber + 1; - /* Only inside file table. */ - UPB_DEFTYPE_FILE = 0, - UPB_DEFTYPE_LAYOUT = 1 -} upb_deftype_t; + // A full validation would also check that each range is disjoint, and that + // none of the fields overlap with the extension ranges, but we are just + // sanity checking here. + if (start < 1 || end <= start || end > max) { + _upb_DefBuilder_Errf(ctx, + "Extension range (%d, %d) is invalid, message=%s\n", + (int)start, (int)end, upb_MessageDef_FullName(m)); + } -#define FIELD_TYPE_UNSPECIFIED 0 + r[i].start = start; + r[i].end = end; + UBP_DEF_SET_OPTIONS(r[i].opts, DescriptorProto_ExtensionRange, + ExtensionRangeOptions, protos[i]); + } -static upb_deftype_t deftype(upb_value v) { - uintptr_t num = (uintptr_t)upb_value_getconstptr(v); - return num & UPB_DEFTYPE_MASK; + return r; } -static const void* unpack_def(upb_value v, upb_deftype_t type) { - uintptr_t num = (uintptr_t)upb_value_getconstptr(v); - return (num & UPB_DEFTYPE_MASK) == type - ? (const void*)(num & ~UPB_DEFTYPE_MASK) - : NULL; -} -static upb_value pack_def(const void* ptr, upb_deftype_t type) { - // Our 3-bit pointer tagging requires all pointers to be multiples of 8. - // The arena will always yield 8-byte-aligned addresses, however we put - // the defs into arrays. For each element in the array to be 8-byte-aligned, - // the sizes of each def type must also be a multiple of 8. - // - // If any of these asserts fail, we need to add or remove padding on 32-bit - // machines (64-bit machines will have 8-byte alignment already due to - // pointers, which all of these structs have). - UPB_ASSERT((sizeof(upb_FieldDef) & UPB_DEFTYPE_MASK) == 0); - UPB_ASSERT((sizeof(upb_MessageDef) & UPB_DEFTYPE_MASK) == 0); - UPB_ASSERT((sizeof(upb_EnumDef) & UPB_DEFTYPE_MASK) == 0); - UPB_ASSERT((sizeof(upb_EnumValueDef) & UPB_DEFTYPE_MASK) == 0); - UPB_ASSERT((sizeof(upb_ServiceDef) & UPB_DEFTYPE_MASK) == 0); - UPB_ASSERT((sizeof(upb_OneofDef) & UPB_DEFTYPE_MASK) == 0); - uintptr_t num = (uintptr_t)ptr; - UPB_ASSERT((num & UPB_DEFTYPE_MASK) == 0); - num |= type; - return upb_value_constptr((const void*)num); -} +#include +#include -/* isalpha() etc. from are locale-dependent, which we don't want. */ -static bool upb_isbetween(uint8_t c, uint8_t low, uint8_t high) { - return c >= low && c <= high; -} -static char upb_ascii_lower(char ch) { - // Per ASCII this will lower-case a letter. If the result is a letter, the - // input was definitely a letter. If the output is not a letter, this may - // have transformed the character unpredictably. - return ch | 0x20; -} +// Must be last. -static bool upb_isletter(char c) { - char lower = upb_ascii_lower(c); - return upb_isbetween(lower, 'a', 'z') || c == '_'; -} +#define UPB_FIELD_TYPE_UNSPECIFIED 0 -static bool upb_isalphanum(char c) { - return upb_isletter(c) || upb_isbetween(c, '0', '9'); -} +typedef struct { + size_t len; + char str[1]; // Null-terminated string data follows. +} str_t; -static const char* shortdefname(const char* fullname) { - const char* p; +struct upb_FieldDef { + const google_protobuf_FieldOptions* opts; + const upb_FileDef* file; + const upb_MessageDef* msgdef; + const char* full_name; + const char* json_name; + union { + int64_t sint; + uint64_t uint; + double dbl; + float flt; + bool boolean; + str_t* str; + } defaultval; + union { + const upb_OneofDef* oneof; + const upb_MessageDef* extension_scope; + } scope; + union { + const upb_MessageDef* msgdef; + const upb_EnumDef* enumdef; + const google_protobuf_FieldDescriptorProto* unresolved; + } sub; + uint32_t number_; + uint16_t index_; + uint16_t layout_index; // Index into msgdef->layout->fields or file->exts + bool has_default; + bool is_extension_; + bool is_packed_; + bool proto3_optional_; + bool has_json_name_; + upb_FieldType type_; + upb_Label label_; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif +}; - if (fullname == NULL) { - return NULL; - } else if ((p = strrchr(fullname, '.')) == NULL) { - /* No '.' in the name, return the full string. */ - return fullname; - } else { - /* Return one past the last '.'. */ - return p + 1; - } +upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i) { + return (upb_FieldDef*)&f[i]; } -/* All submessage fields are lower than all other fields. - * Secondly, fields are increasing in order. */ -uint32_t field_rank(const upb_FieldDef* f) { - uint32_t ret = upb_FieldDef_Number(f); - const uint32_t high_bit = 1 << 30; - UPB_ASSERT(ret < high_bit); - if (!upb_FieldDef_IsSubMessage(f)) ret |= high_bit; - return ret; +const google_protobuf_FieldOptions* upb_FieldDef_Options(const upb_FieldDef* f) { + return f->opts; } -int cmp_fields(const void* p1, const void* p2) { - const upb_FieldDef* f1 = *(upb_FieldDef* const*)p1; - const upb_FieldDef* f2 = *(upb_FieldDef* const*)p2; - return field_rank(f1) - field_rank(f2); +bool upb_FieldDef_HasOptions(const upb_FieldDef* f) { + return f->opts != (void*)kUpbDefOptDefault; } -static void upb_Status_setoom(upb_Status* status) { - upb_Status_SetErrorMessage(status, "out of memory"); +const char* upb_FieldDef_FullName(const upb_FieldDef* f) { + return f->full_name; } -static void assign_msg_wellknowntype(upb_MessageDef* m) { - const char* name = upb_MessageDef_FullName(m); - if (name == NULL) { - m->well_known_type = kUpb_WellKnown_Unspecified; - return; - } - if (!strcmp(name, "google.protobuf.Any")) { - m->well_known_type = kUpb_WellKnown_Any; - } else if (!strcmp(name, "google.protobuf.FieldMask")) { - m->well_known_type = kUpb_WellKnown_FieldMask; - } else if (!strcmp(name, "google.protobuf.Duration")) { - m->well_known_type = kUpb_WellKnown_Duration; - } else if (!strcmp(name, "google.protobuf.Timestamp")) { - m->well_known_type = kUpb_WellKnown_Timestamp; - } else if (!strcmp(name, "google.protobuf.DoubleValue")) { - m->well_known_type = kUpb_WellKnown_DoubleValue; - } else if (!strcmp(name, "google.protobuf.FloatValue")) { - m->well_known_type = kUpb_WellKnown_FloatValue; - } else if (!strcmp(name, "google.protobuf.Int64Value")) { - m->well_known_type = kUpb_WellKnown_Int64Value; - } else if (!strcmp(name, "google.protobuf.UInt64Value")) { - m->well_known_type = kUpb_WellKnown_UInt64Value; - } else if (!strcmp(name, "google.protobuf.Int32Value")) { - m->well_known_type = kUpb_WellKnown_Int32Value; - } else if (!strcmp(name, "google.protobuf.UInt32Value")) { - m->well_known_type = kUpb_WellKnown_UInt32Value; - } else if (!strcmp(name, "google.protobuf.BoolValue")) { - m->well_known_type = kUpb_WellKnown_BoolValue; - } else if (!strcmp(name, "google.protobuf.StringValue")) { - m->well_known_type = kUpb_WellKnown_StringValue; - } else if (!strcmp(name, "google.protobuf.BytesValue")) { - m->well_known_type = kUpb_WellKnown_BytesValue; - } else if (!strcmp(name, "google.protobuf.Value")) { - m->well_known_type = kUpb_WellKnown_Value; - } else if (!strcmp(name, "google.protobuf.ListValue")) { - m->well_known_type = kUpb_WellKnown_ListValue; - } else if (!strcmp(name, "google.protobuf.Struct")) { - m->well_known_type = kUpb_WellKnown_Struct; - } else { - m->well_known_type = kUpb_WellKnown_Unspecified; +upb_CType upb_FieldDef_CType(const upb_FieldDef* f) { + switch (f->type_) { + case kUpb_FieldType_Double: + return kUpb_CType_Double; + case kUpb_FieldType_Float: + return kUpb_CType_Float; + case kUpb_FieldType_Int64: + case kUpb_FieldType_SInt64: + case kUpb_FieldType_SFixed64: + return kUpb_CType_Int64; + case kUpb_FieldType_Int32: + case kUpb_FieldType_SFixed32: + case kUpb_FieldType_SInt32: + return kUpb_CType_Int32; + case kUpb_FieldType_UInt64: + case kUpb_FieldType_Fixed64: + return kUpb_CType_UInt64; + case kUpb_FieldType_UInt32: + case kUpb_FieldType_Fixed32: + return kUpb_CType_UInt32; + case kUpb_FieldType_Enum: + return kUpb_CType_Enum; + case kUpb_FieldType_Bool: + return kUpb_CType_Bool; + case kUpb_FieldType_String: + return kUpb_CType_String; + case kUpb_FieldType_Bytes: + return kUpb_CType_Bytes; + case kUpb_FieldType_Group: + case kUpb_FieldType_Message: + return kUpb_CType_Message; } + UPB_UNREACHABLE(); } -/* upb_EnumDef ****************************************************************/ +upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f) { return f->type_; } -const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e) { - return e->opts; -} +uint32_t upb_FieldDef_Index(const upb_FieldDef* f) { return f->index_; } -bool upb_EnumDef_HasOptions(const upb_EnumDef* e) { - return e->opts != (void*)opt_default; +upb_Label upb_FieldDef_Label(const upb_FieldDef* f) { return f->label_; } + +uint32_t upb_FieldDef_Number(const upb_FieldDef* f) { return f->number_; } + +bool upb_FieldDef_IsExtension(const upb_FieldDef* f) { + return f->is_extension_; } -const char* upb_EnumDef_FullName(const upb_EnumDef* e) { return e->full_name; } +bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { return f->is_packed_; } -const char* upb_EnumDef_Name(const upb_EnumDef* e) { - return shortdefname(e->full_name); +const char* upb_FieldDef_Name(const upb_FieldDef* f) { + return _upb_DefBuilder_FullToShort(f->full_name); } -const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e) { return e->file; } +const char* upb_FieldDef_JsonName(const upb_FieldDef* f) { + return f->json_name; +} -const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e) { - return e->containing_type; +bool upb_FieldDef_HasJsonName(const upb_FieldDef* f) { + return f->has_json_name_; } -int32_t upb_EnumDef_Default(const upb_EnumDef* e) { - UPB_ASSERT(upb_EnumDef_FindValueByNumber(e, e->defaultval)); - return e->defaultval; +const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f) { return f->file; } + +const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f) { + return f->msgdef; } -int upb_EnumDef_ValueCount(const upb_EnumDef* e) { return e->value_count; } +const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f) { + return f->is_extension_ ? f->scope.extension_scope : NULL; +} -const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( - const upb_EnumDef* def, const char* name, size_t len) { - upb_value v; - return upb_strtable_lookup2(&def->ntoi, name, len, &v) - ? upb_value_getconstptr(v) - : NULL; +const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f) { + return f->is_extension_ ? NULL : f->scope.oneof; } -const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* def, - int32_t num) { - upb_value v; - return upb_inttable_lookup(&def->iton, num, &v) ? upb_value_getconstptr(v) - : NULL; +const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f) { + const upb_OneofDef* oneof = upb_FieldDef_ContainingOneof(f); + if (!oneof || upb_OneofDef_IsSynthetic(oneof)) return NULL; + return oneof; } -bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num) { - // We could use upb_EnumDef_FindValueByNumber(e, num) != NULL, but we expect - // this to be faster (especially for small numbers). - return upb_MiniTable_Enum_CheckValue(e->layout, num); +upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f) { + UPB_ASSERT(!upb_FieldDef_IsSubMessage(f)); + upb_MessageValue ret; + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + return (upb_MessageValue){.bool_val = f->defaultval.boolean}; + case kUpb_CType_Int64: + return (upb_MessageValue){.int64_val = f->defaultval.sint}; + case kUpb_CType_UInt64: + return (upb_MessageValue){.uint64_val = f->defaultval.uint}; + case kUpb_CType_Enum: + case kUpb_CType_Int32: + return (upb_MessageValue){.int32_val = (int32_t)f->defaultval.sint}; + case kUpb_CType_UInt32: + return (upb_MessageValue){.uint32_val = (uint32_t)f->defaultval.uint}; + case kUpb_CType_Float: + return (upb_MessageValue){.float_val = f->defaultval.flt}; + case kUpb_CType_Double: + return (upb_MessageValue){.double_val = f->defaultval.dbl}; + case kUpb_CType_String: + case kUpb_CType_Bytes: { + str_t* str = f->defaultval.str; + if (str) { + return (upb_MessageValue){ + .str_val = (upb_StringView){.data = str->str, .size = str->len}}; + } else { + return (upb_MessageValue){ + .str_val = (upb_StringView){.data = NULL, .size = 0}}; + } + } + default: + UPB_UNREACHABLE(); + } + + return ret; } -const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i) { - UPB_ASSERT(0 <= i && i < e->value_count); - return &e->values[i]; +const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Message ? f->sub.msgdef : NULL; } -/* upb_EnumValueDef ***********************************************************/ - -const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( - const upb_EnumValueDef* e) { - return e->opts; +const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Enum ? f->sub.enumdef : NULL; } -bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* e) { - return e->opts != (void*)opt_default; +const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f) { + UPB_ASSERT(!upb_FieldDef_IsExtension(f)); + const upb_MiniTable* layout = upb_MessageDef_MiniTable(f->msgdef); + return &layout->fields[f->layout_index]; } -const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* ev) { - return ev->parent; +const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable( + const upb_FieldDef* f) { + UPB_ASSERT(upb_FieldDef_IsExtension(f)); + const upb_FileDef* file = upb_FieldDef_File(f); + return _upb_FileDef_ExtensionMiniTable(file, f->layout_index); } -const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* ev) { - return ev->full_name; -} +bool _upb_FieldDef_IsClosedEnum(const upb_FieldDef* f) { + if (UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3) return false; + if (f->type_ != kUpb_FieldType_Enum) return false; -const char* upb_EnumValueDef_Name(const upb_EnumValueDef* ev) { - return shortdefname(ev->full_name); -} + // TODO(https://github.com/protocolbuffers/upb/issues/541): + // fix map enum values to check for unknown enum values and put + // them in the unknown field set. + if (upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f))) { + return false; + } -int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* ev) { - return ev->number; + // TODO: Maybe make is_proto2 a bool at creation? + const upb_FileDef* file = upb_EnumDef_File(f->sub.enumdef); + return upb_FileDef_Syntax(file) == kUpb_Syntax_Proto2; } -uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* ev) { - // Compute index in our parent's array. - return ev - ev->parent->values; +bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) { + return f->proto3_optional_; } -/* upb_ExtensionRange - * ***************************************************************/ +int _upb_FieldDef_LayoutIndex(const upb_FieldDef* f) { return f->layout_index; } -const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( - const upb_ExtensionRange* r) { - return r->opts; +uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f) { + uint64_t out = f->is_packed_ ? kUpb_FieldModifier_IsPacked : 0; + + switch (f->label_) { + case kUpb_Label_Optional: + if (!upb_FieldDef_HasPresence(f)) { + out |= kUpb_FieldModifier_IsProto3Singular; + } + break; + case kUpb_Label_Repeated: + out |= kUpb_FieldModifier_IsRepeated; + break; + case kUpb_Label_Required: + out |= kUpb_FieldModifier_IsRequired; + break; + } + + if (_upb_FieldDef_IsClosedEnum(f)) { + out |= kUpb_FieldModifier_IsClosedEnum; + } + return out; } -bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r) { - return r->opts != (void*)opt_default; +bool upb_FieldDef_HasDefault(const upb_FieldDef* f) { return f->has_default; } + +bool upb_FieldDef_HasPresence(const upb_FieldDef* f) { + if (upb_FieldDef_IsRepeated(f)) return false; + const upb_FileDef* file = upb_FieldDef_File(f); + return upb_FieldDef_IsSubMessage(f) || upb_FieldDef_ContainingOneof(f) || + upb_FileDef_Syntax(file) == kUpb_Syntax_Proto2; } -int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* e) { - return e->start; +bool upb_FieldDef_HasSubDef(const upb_FieldDef* f) { + return upb_FieldDef_IsSubMessage(f) || + upb_FieldDef_CType(f) == kUpb_CType_Enum; } -int32_t upb_ExtensionRange_End(const upb_ExtensionRange* e) { return e->end; } +bool upb_FieldDef_IsMap(const upb_FieldDef* f) { + return upb_FieldDef_IsRepeated(f) && upb_FieldDef_IsSubMessage(f) && + upb_MessageDef_IsMapEntry(upb_FieldDef_MessageSubDef(f)); +} -/* upb_FieldDef ***************************************************************/ +bool upb_FieldDef_IsOptional(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Optional; +} -const google_protobuf_FieldOptions* upb_FieldDef_Options( - const upb_FieldDef* f) { - return f->opts; +bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f) { + return !upb_FieldDef_IsString(f) && !upb_FieldDef_IsSubMessage(f); } -bool upb_FieldDef_HasOptions(const upb_FieldDef* f) { - return f->opts != (void*)opt_default; +bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Repeated; } -const char* upb_FieldDef_FullName(const upb_FieldDef* f) { - return f->full_name; +bool upb_FieldDef_IsRequired(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Required; } -upb_CType upb_FieldDef_CType(const upb_FieldDef* f) { - switch (f->type_) { - case kUpb_FieldType_Double: - return kUpb_CType_Double; - case kUpb_FieldType_Float: - return kUpb_CType_Float; - case kUpb_FieldType_Int64: - case kUpb_FieldType_SInt64: - case kUpb_FieldType_SFixed64: - return kUpb_CType_Int64; - case kUpb_FieldType_Int32: - case kUpb_FieldType_SFixed32: - case kUpb_FieldType_SInt32: - return kUpb_CType_Int32; - case kUpb_FieldType_UInt64: - case kUpb_FieldType_Fixed64: - return kUpb_CType_UInt64; - case kUpb_FieldType_UInt32: - case kUpb_FieldType_Fixed32: - return kUpb_CType_UInt32; - case kUpb_FieldType_Enum: - return kUpb_CType_Enum; - case kUpb_FieldType_Bool: - return kUpb_CType_Bool; - case kUpb_FieldType_String: - return kUpb_CType_String; - case kUpb_FieldType_Bytes: - return kUpb_CType_Bytes; - case kUpb_FieldType_Group: - case kUpb_FieldType_Message: - return kUpb_CType_Message; - } - UPB_UNREACHABLE(); +bool upb_FieldDef_IsString(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_String || + upb_FieldDef_CType(f) == kUpb_CType_Bytes; } -upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f) { return f->type_; } +bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Message; +} -uint32_t upb_FieldDef_Index(const upb_FieldDef* f) { return f->index_; } +static bool between(int32_t x, int32_t low, int32_t high) { + return x >= low && x <= high; +} -upb_Label upb_FieldDef_Label(const upb_FieldDef* f) { return f->label_; } +bool upb_FieldDef_checklabel(int32_t label) { return between(label, 1, 3); } +bool upb_FieldDef_checktype(int32_t type) { return between(type, 1, 11); } +bool upb_FieldDef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); } -uint32_t upb_FieldDef_Number(const upb_FieldDef* f) { return f->number_; } +bool upb_FieldDef_checkdescriptortype(int32_t type) { + return between(type, 1, 18); +} -bool upb_FieldDef_IsExtension(const upb_FieldDef* f) { - return f->is_extension_; +static bool streql2(const char* a, size_t n, const char* b) { + return n == strlen(b) && memcmp(a, b, n) == 0; } -bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { return f->packed_; } +// Implement the transformation as described in the spec: +// 1. upper case all letters after an underscore. +// 2. remove all underscores. +static char* make_json_name(const char* name, size_t size, upb_Arena* a) { + char* out = upb_Arena_Malloc(a, size + 1); // +1 is to add a trailing '\0' + if (out == NULL) return NULL; -const char* upb_FieldDef_Name(const upb_FieldDef* f) { - return shortdefname(f->full_name); + bool ucase_next = false; + char* des = out; + for (size_t i = 0; i < size; i++) { + if (name[i] == '_') { + ucase_next = true; + } else { + *des++ = ucase_next ? toupper(name[i]) : name[i]; + ucase_next = false; + } + } + *des++ = '\0'; + return out; } -const char* upb_FieldDef_JsonName(const upb_FieldDef* f) { - return f->json_name; +static str_t* newstr(upb_DefBuilder* ctx, const char* data, size_t len) { + str_t* ret = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); + if (!ret) _upb_DefBuilder_OomErr(ctx); + ret->len = len; + if (len) memcpy(ret->str, data, len); + ret->str[len] = '\0'; + return ret; } -bool upb_FieldDef_HasJsonName(const upb_FieldDef* f) { - return f->has_json_name_; -} +static str_t* unescape(upb_DefBuilder* ctx, const upb_FieldDef* f, + const char* data, size_t len) { + // Size here is an upper bound; escape sequences could ultimately shrink it. + str_t* ret = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); + char* dst = &ret->str[0]; + const char* src = data; + const char* end = data + len; -const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f) { return f->file; } + while (src < end) { + if (*src == '\\') { + src++; + *dst++ = _upb_DefBuilder_ParseEscape(ctx, f, &src, end); + } else { + *dst++ = *src++; + } + } -const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f) { - return f->msgdef; + ret->len = dst - &ret->str[0]; + return ret; } -const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f) { - return f->is_extension_ ? f->scope.extension_scope : NULL; -} +static void parse_default(upb_DefBuilder* ctx, const char* str, size_t len, + upb_FieldDef* f) { + char* end; + char nullz[64]; + errno = 0; -const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f) { - return f->is_extension_ ? NULL : f->scope.oneof; -} + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Int32: + case kUpb_CType_Int64: + case kUpb_CType_UInt32: + case kUpb_CType_UInt64: + case kUpb_CType_Double: + case kUpb_CType_Float: + /* Standard C number parsing functions expect null-terminated strings. */ + if (len >= sizeof(nullz) - 1) { + _upb_DefBuilder_Errf(ctx, "Default too long: %.*s", (int)len, str); + } + memcpy(nullz, str, len); + nullz[len] = '\0'; + str = nullz; + break; + default: + break; + } -const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f) { - const upb_OneofDef* oneof = upb_FieldDef_ContainingOneof(f); - if (!oneof || upb_OneofDef_IsSynthetic(oneof)) return NULL; - return oneof; -} + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Int32: { + long val = strtol(str, &end, 0); + if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.sint = val; + break; + } + case kUpb_CType_Enum: { + const upb_EnumDef* e = f->sub.enumdef; + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByNameWithSize(e, str, len); + if (!ev) { + goto invalid; + } + f->defaultval.sint = upb_EnumValueDef_Number(ev); + break; + } + case kUpb_CType_Int64: { + long long val = strtoll(str, &end, 0); + if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.sint = val; + break; + } + case kUpb_CType_UInt32: { + unsigned long val = strtoul(str, &end, 0); + if (val > UINT32_MAX || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.uint = val; + break; + } + case kUpb_CType_UInt64: { + unsigned long long val = strtoull(str, &end, 0); + if (val > UINT64_MAX || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.uint = val; + break; + } + case kUpb_CType_Double: { + double val = strtod(str, &end); + if (errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.dbl = val; + break; + } + case kUpb_CType_Float: { + float val = strtof(str, &end); + if (errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.flt = val; + break; + } + case kUpb_CType_Bool: { + if (streql2(str, len, "false")) { + f->defaultval.boolean = false; + } else if (streql2(str, len, "true")) { + f->defaultval.boolean = true; + } else { + goto invalid; + } + break; + } + case kUpb_CType_String: + f->defaultval.str = newstr(ctx, str, len); + break; + case kUpb_CType_Bytes: + f->defaultval.str = unescape(ctx, f, str, len); + break; + case kUpb_CType_Message: + /* Should not have a default value. */ + _upb_DefBuilder_Errf(ctx, "Message should not have a default (%s)", + upb_FieldDef_FullName(f)); + } -upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f) { - UPB_ASSERT(!upb_FieldDef_IsSubMessage(f)); - upb_MessageValue ret; + return; +invalid: + _upb_DefBuilder_Errf(ctx, "Invalid default '%.*s' for field %s of type %d", + (int)len, str, upb_FieldDef_FullName(f), + (int)upb_FieldDef_Type(f)); +} + +static void set_default_default(upb_DefBuilder* ctx, upb_FieldDef* f) { switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Bool: - return (upb_MessageValue){.bool_val = f->defaultval.boolean}; + case kUpb_CType_Int32: case kUpb_CType_Int64: - return (upb_MessageValue){.int64_val = f->defaultval.sint}; + f->defaultval.sint = 0; + break; case kUpb_CType_UInt64: - return (upb_MessageValue){.uint64_val = f->defaultval.uint}; - case kUpb_CType_Enum: - case kUpb_CType_Int32: - return (upb_MessageValue){.int32_val = (int32_t)f->defaultval.sint}; case kUpb_CType_UInt32: - return (upb_MessageValue){.uint32_val = (uint32_t)f->defaultval.uint}; - case kUpb_CType_Float: - return (upb_MessageValue){.float_val = f->defaultval.flt}; + f->defaultval.uint = 0; + break; case kUpb_CType_Double: - return (upb_MessageValue){.double_val = f->defaultval.dbl}; + case kUpb_CType_Float: + f->defaultval.dbl = 0; + break; case kUpb_CType_String: - case kUpb_CType_Bytes: { - str_t* str = f->defaultval.str; - if (str) { - return (upb_MessageValue){ - .str_val = (upb_StringView){.data = str->str, .size = str->len}}; - } else { - return (upb_MessageValue){ - .str_val = (upb_StringView){.data = NULL, .size = 0}}; - } + case kUpb_CType_Bytes: + f->defaultval.str = newstr(ctx, NULL, 0); + break; + case kUpb_CType_Bool: + f->defaultval.boolean = false; + break; + case kUpb_CType_Enum: { + const upb_EnumValueDef* v = upb_EnumDef_Value(f->sub.enumdef, 0); + f->defaultval.sint = upb_EnumValueDef_Number(v); } - default: - UPB_UNREACHABLE(); + case kUpb_CType_Message: + break; } - - return ret; } -const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Message ? f->sub.msgdef : NULL; -} - -const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Enum ? f->sub.enumdef : NULL; -} +static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_FieldDescriptorProto* field_proto, + upb_MessageDef* m, upb_FieldDef* f) { + // Must happen before _upb_DefBuilder_Add() + f->file = _upb_DefBuilder_File(ctx); -const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f) { - UPB_ASSERT(!upb_FieldDef_IsExtension(f)); - return &f->msgdef->layout->fields[f->layout_index]; -} + if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { + _upb_DefBuilder_Errf(ctx, "field has no name"); + } -const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable( - const upb_FieldDef* f) { - UPB_ASSERT(upb_FieldDef_IsExtension(f)); - return f->file->ext_layouts[f->layout_index]; -} + const upb_StringView name = google_protobuf_FieldDescriptorProto_name(field_proto); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); -bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) { - return f->proto3_optional_; -} + f->has_json_name_ = google_protobuf_FieldDescriptorProto_has_json_name(field_proto); + if (f->has_json_name_) { + const upb_StringView sv = + google_protobuf_FieldDescriptorProto_json_name(field_proto); + f->json_name = upb_strdup2(sv.data, sv.size, ctx->arena); + } else { + f->json_name = make_json_name(name.data, name.size, ctx->arena); + } + if (!f->json_name) _upb_DefBuilder_OomErr(ctx); -bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Message; -} + f->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto); + f->number_ = google_protobuf_FieldDescriptorProto_number(field_proto); + f->proto3_optional_ = + google_protobuf_FieldDescriptorProto_proto3_optional(field_proto); + f->msgdef = m; + f->scope.oneof = NULL; -bool upb_FieldDef_IsString(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_String || - upb_FieldDef_CType(f) == kUpb_CType_Bytes; -} + const bool has_type = google_protobuf_FieldDescriptorProto_has_type(field_proto); + const bool has_type_name = + google_protobuf_FieldDescriptorProto_has_type_name(field_proto); -bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) { - return upb_FieldDef_Label(f) == kUpb_Label_Repeated; -} + f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto); -bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f) { - return !upb_FieldDef_IsString(f) && !upb_FieldDef_IsSubMessage(f); -} + if (has_type) { + switch (f->type_) { + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + case kUpb_FieldType_Enum: + if (!has_type_name) { + _upb_DefBuilder_Errf(ctx, "field of type %d requires type name (%s)", + (int)f->type_, f->full_name); + } + break; + default: + if (has_type_name) { + _upb_DefBuilder_Errf( + ctx, "invalid type for field with type_name set (%s, %d)", + f->full_name, (int)f->type_); + } + } + } else if (has_type_name) { + f->type_ = + UPB_FIELD_TYPE_UNSPECIFIED; // We'll fill this in in resolve_fielddef() + } -bool upb_FieldDef_IsMap(const upb_FieldDef* f) { - return upb_FieldDef_IsRepeated(f) && upb_FieldDef_IsSubMessage(f) && - upb_MessageDef_IsMapEntry(upb_FieldDef_MessageSubDef(f)); -} + if (f->type_ < kUpb_FieldType_Double || f->type_ > kUpb_FieldType_SInt64) { + _upb_DefBuilder_Errf(ctx, "invalid type for field %s (%d)", f->full_name, + f->type_); + } -bool upb_FieldDef_HasDefault(const upb_FieldDef* f) { return f->has_default; } + if (f->label_ < kUpb_Label_Optional || f->label_ > kUpb_Label_Repeated) { + _upb_DefBuilder_Errf(ctx, "invalid label for field %s (%d)", f->full_name, + f->label_); + } -bool upb_FieldDef_HasSubDef(const upb_FieldDef* f) { - return upb_FieldDef_IsSubMessage(f) || - upb_FieldDef_CType(f) == kUpb_CType_Enum; -} + /* We can't resolve the subdef or (in the case of extensions) the containing + * message yet, because it may not have been defined yet. We stash a pointer + * to the field_proto until later when we can properly resolve it. */ + f->sub.unresolved = field_proto; -bool upb_FieldDef_HasPresence(const upb_FieldDef* f) { - if (upb_FieldDef_IsRepeated(f)) return false; - return upb_FieldDef_IsSubMessage(f) || upb_FieldDef_ContainingOneof(f) || - f->file->syntax == kUpb_Syntax_Proto2; -} + if (f->label_ == kUpb_Label_Required && + upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3) { + _upb_DefBuilder_Errf(ctx, "proto3 fields cannot be required (%s)", + f->full_name); + } -static bool between(int32_t x, int32_t low, int32_t high) { - return x >= low && x <= high; -} + if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + uint32_t oneof_index = google_protobuf_FieldDescriptorProto_oneof_index(field_proto); -bool upb_FieldDef_checklabel(int32_t label) { return between(label, 1, 3); } -bool upb_FieldDef_checktype(int32_t type) { return between(type, 1, 11); } -bool upb_FieldDef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); } + if (upb_FieldDef_Label(f) != kUpb_Label_Optional) { + _upb_DefBuilder_Errf(ctx, "fields in oneof must have OPTIONAL label (%s)", + f->full_name); + } -bool upb_FieldDef_checkdescriptortype(int32_t type) { - return between(type, 1, 18); -} + if (!m) { + _upb_DefBuilder_Errf(ctx, "oneof field (%s) has no containing msg", + f->full_name); + } -/* upb_MessageDef - * *****************************************************************/ + if (oneof_index >= upb_MessageDef_OneofCount(m)) { + _upb_DefBuilder_Errf(ctx, "oneof_index out of range (%s)", f->full_name); + } -const google_protobuf_MessageOptions* upb_MessageDef_Options( - const upb_MessageDef* m) { - return m->opts; -} + upb_OneofDef* oneof = (upb_OneofDef*)upb_MessageDef_Oneof(m, oneof_index); + f->scope.oneof = oneof; -bool upb_MessageDef_HasOptions(const upb_MessageDef* m) { - return m->opts != (void*)opt_default; -} + bool ok = _upb_OneofDef_Insert(oneof, f, name.data, name.size, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + } -const char* upb_MessageDef_FullName(const upb_MessageDef* m) { - return m->full_name; -} + UBP_DEF_SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); -const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m) { - return m->file; + if (google_protobuf_FieldOptions_has_packed(f->opts)) { + f->is_packed_ = google_protobuf_FieldOptions_packed(f->opts); + } else { + // Repeated fields default to packed for proto3 only. + f->is_packed_ = upb_FieldDef_IsPrimitive(f) && + f->label_ == kUpb_Label_Repeated && + upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3; + } } -const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m) { - return m->containing_type; -} +static void _upb_FieldDef_CreateExt( + upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m, + upb_FieldDef* f) { + _upb_FieldDef_Create(ctx, prefix, field_proto, m, f); + f->is_extension_ = true; -const char* upb_MessageDef_Name(const upb_MessageDef* m) { - return shortdefname(m->full_name); -} + if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + _upb_DefBuilder_Errf(ctx, "oneof_index provided for extension field (%s)", + f->full_name); + } -upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m) { - return m->file->syntax; -} + f->scope.extension_scope = m; + _upb_DefBuilder_Add(ctx, f->full_name, _upb_DefType_Pack(f, UPB_DEFTYPE_EXT)); + f->layout_index = ctx->ext_count++; -const upb_FieldDef* upb_MessageDef_FindFieldByNumber(const upb_MessageDef* m, - uint32_t i) { - upb_value val; - return upb_inttable_lookup(&m->itof, i, &val) ? upb_value_getconstptr(val) - : NULL; + if (ctx->layout) { + UPB_ASSERT(_upb_FieldDef_ExtensionMiniTable(f)->field.number == f->number_); + } } -const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( - const upb_MessageDef* m, const char* name, size_t len) { - upb_value val; +static void _upb_FieldDef_CreateNotExt( + upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m, + upb_FieldDef* f) { + _upb_FieldDef_Create(ctx, prefix, field_proto, m, f); + f->is_extension_ = false; - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return NULL; + if (!google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + if (f->proto3_optional_) { + _upb_DefBuilder_Errf( + ctx, + "non-extension field (%s) with proto3_optional was not in a oneof", + f->full_name); + } } - return unpack_def(val, UPB_DEFTYPE_FIELD); -} + _upb_MessageDef_InsertField(ctx, m, f); -const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( - const upb_MessageDef* m, const char* name, size_t len) { - upb_value val; + if (!ctx->layout) return; - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return NULL; + const upb_MiniTable* mt = upb_MessageDef_MiniTable(m); + const upb_MiniTable_Field* fields = mt->fields; + for (int i = 0; i < mt->field_count; i++) { + if (fields[i].number == f->number_) { + f->layout_index = i; + return; + } } - return unpack_def(val, UPB_DEFTYPE_ONEOF); + UPB_ASSERT(false); // It should be impossible to reach this point. } -bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, - const char* name, size_t len, - const upb_FieldDef** out_f, - const upb_OneofDef** out_o) { - upb_value val; +upb_FieldDef* _upb_FieldDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_FieldDescriptorProto* const* protos, const char* prefix, + upb_MessageDef* m, bool* is_sorted) { + _upb_DefType_CheckPadding(sizeof(upb_FieldDef)); + upb_FieldDef* defs = + (upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n); - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return false; - } + // If we are creating extensions then is_sorted will be NULL. + // If we are not creating extensions then is_sorted will be non-NULL. + if (is_sorted) { + uint32_t previous = 0; + for (int i = 0; i < n; i++) { + upb_FieldDef* f = &defs[i]; - const upb_FieldDef* f = unpack_def(val, UPB_DEFTYPE_FIELD); - const upb_OneofDef* o = unpack_def(val, UPB_DEFTYPE_ONEOF); - if (out_f) *out_f = f; - if (out_o) *out_o = o; - return f || o; /* False if this was a JSON name. */ -} + _upb_FieldDef_CreateNotExt(ctx, prefix, protos[i], m, f); + f->index_ = i; + if (!ctx->layout) f->layout_index = i; -const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( - const upb_MessageDef* m, const char* name, size_t len) { - upb_value val; - const upb_FieldDef* f; + const uint32_t current = f->number_; + if (previous > current) *is_sorted = false; + previous = current; + } + } else { + for (int i = 0; i < n; i++) { + upb_FieldDef* f = &defs[i]; - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return NULL; + _upb_FieldDef_CreateExt(ctx, prefix, protos[i], m, f); + f->index_ = i; + } } - f = unpack_def(val, UPB_DEFTYPE_FIELD); - if (!f) f = unpack_def(val, UPB_DEFTYPE_FIELD_JSONNAME); - - return f; + return defs; } -int upb_MessageDef_numfields(const upb_MessageDef* m) { return m->field_count; } - -int upb_MessageDef_numoneofs(const upb_MessageDef* m) { return m->oneof_count; } - -int upb_MessageDef_numrealoneofs(const upb_MessageDef* m) { - return m->real_oneof_count; +static void resolve_subdef(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f) { + const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; + upb_StringView name = + google_protobuf_FieldDescriptorProto_type_name(field_proto); + bool has_name = + google_protobuf_FieldDescriptorProto_has_type_name(field_proto); + switch ((int)f->type_) { + case UPB_FIELD_TYPE_UNSPECIFIED: { + // Type was not specified and must be inferred. + UPB_ASSERT(has_name); + upb_deftype_t type; + const void* def = + _upb_DefBuilder_ResolveAny(ctx, f->full_name, prefix, name, &type); + switch (type) { + case UPB_DEFTYPE_ENUM: + f->sub.enumdef = def; + f->type_ = kUpb_FieldType_Enum; + break; + case UPB_DEFTYPE_MSG: + f->sub.msgdef = def; + f->type_ = kUpb_FieldType_Message; // It appears there is no way of + // this being a group. + break; + default: + _upb_DefBuilder_Errf(ctx, "Couldn't resolve type name for field %s", + f->full_name); + } + } + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + UPB_ASSERT(has_name); + f->sub.msgdef = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, + UPB_DEFTYPE_MSG); + break; + case kUpb_FieldType_Enum: + UPB_ASSERT(has_name); + f->sub.enumdef = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, + UPB_DEFTYPE_ENUM); + break; + default: + // No resolution necessary. + break; + } } -int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) { - return m->ext_range_count; +static int _upb_FieldDef_Compare(const void* p1, const void* p2) { + const uint32_t v1 = (*(upb_FieldDef**)p1)->number_; + const uint32_t v2 = (*(upb_FieldDef**)p2)->number_; + return (v1 < v2) ? -1 : (v1 > v2); } -int upb_MessageDef_FieldCount(const upb_MessageDef* m) { - return m->field_count; +const upb_FieldDef** _upb_FieldDefs_Sorted(const upb_FieldDef* f, int n, + upb_Arena* a) { + // TODO: Try to replace this arena alloc with a persistent scratch buffer. + upb_FieldDef** out = (upb_FieldDef**)upb_Arena_Malloc(a, n * sizeof(void*)); + if (!out) return NULL; + + for (int i = 0; i < n; i++) { + out[i] = (upb_FieldDef*)&f[i]; + } + qsort(out, n, sizeof(void*), _upb_FieldDef_Compare); + + for (int i = 0; i < n; i++) { + out[i]->layout_index = i; + } + return (const upb_FieldDef**)out; } -int upb_MessageDef_OneofCount(const upb_MessageDef* m) { - return m->oneof_count; -} +bool upb_FieldDef_MiniDescriptorEncode(const upb_FieldDef* f, upb_Arena* a, + upb_StringView* out) { + UPB_ASSERT(f->is_extension_); -int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m) { - return m->nested_msg_count; -} + upb_DescState s; + _upb_DescState_Init(&s); -int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m) { - return m->nested_enum_count; -} + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_StartMessage(&s.e, s.ptr, 0); -int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m) { - return m->nested_ext_count; -} + const int number = upb_FieldDef_Number(f); + const uint64_t modifiers = _upb_FieldDef_Modifiers(f); -int upb_MessageDef_realoneofcount(const upb_MessageDef* m) { - return m->real_oneof_count; -} + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_PutField(&s.e, s.ptr, f->type_, number, modifiers); -const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m) { - return m->layout; -} + if (!_upb_DescState_Grow(&s, a)) return false; + *s.ptr = '\0'; -const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, - int i) { - UPB_ASSERT(0 <= i && i < m->ext_range_count); - return &m->ext_ranges[i]; + out->data = s.buf; + out->size = s.ptr - s.buf; + return true; } -const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->field_count); - return &m->fields[i]; -} +static void resolve_extension(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f, + const google_protobuf_FieldDescriptorProto* field_proto) { + if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) { + _upb_DefBuilder_Errf(ctx, "extension for field '%s' had no extendee", + f->full_name); + } -const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->oneof_count); - return &m->oneofs[i]; -} + upb_StringView name = google_protobuf_FieldDescriptorProto_extendee(field_proto); + const upb_MessageDef* m = + _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); + f->msgdef = m; -const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, - int i) { - UPB_ASSERT(0 <= i && i < m->nested_msg_count); - return &m->nested_msgs[i]; -} + if (!_upb_MessageDef_IsValidExtensionNumber(m, f->number_)) { + _upb_DefBuilder_Errf( + ctx, + "field number %u in extension %s has no extension range in message %s", + (unsigned)f->number_, f->full_name, upb_MessageDef_FullName(m)); + } -const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->nested_enum_count); - return &m->nested_enums[i]; -} + const upb_MiniTable_Extension* ext = _upb_FieldDef_ExtensionMiniTable(f); -const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, - int i) { - UPB_ASSERT(0 <= i && i < m->nested_ext_count); - return &m->nested_exts[i]; -} + if (ctx->layout) { + UPB_ASSERT(upb_FieldDef_Number(f) == ext->field.number); + } else { + upb_StringView desc; + if (!upb_FieldDef_MiniDescriptorEncode(f, ctx->tmp_arena, &desc)) { + _upb_DefBuilder_OomErr(ctx); + } -upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m) { - return m->well_known_type; + upb_MiniTable_Extension* mut_ext = (upb_MiniTable_Extension*)ext; + upb_MiniTable_Sub sub; + sub.submsg = NULL; + sub.subenum = NULL; + bool ok2 = upb_MiniTable_BuildExtension(desc.data, desc.size, mut_ext, + upb_MessageDef_MiniTable(m), sub, + ctx->status); + if (!ok2) _upb_DefBuilder_Errf(ctx, "Could not build extension mini table"); + + assert(mut_ext->field.number == f->number_); + mut_ext->extendee = upb_MessageDef_MiniTable(m); + if (upb_FieldDef_IsSubMessage(f)) { + mut_ext->sub.submsg = upb_MessageDef_MiniTable(f->sub.msgdef); + } else if (mut_ext->field.descriptortype == kUpb_FieldType_Enum) { + mut_ext->sub.subenum = _upb_EnumDef_MiniTable(f->sub.enumdef); + } + } + + bool ok = _upb_DefPool_InsertExt(ctx->symtab, ext, f); + if (!ok) _upb_DefBuilder_OomErr(ctx); } -/* upb_OneofDef ***************************************************************/ +static void resolve_default(upb_DefBuilder* ctx, upb_FieldDef* f, + const google_protobuf_FieldDescriptorProto* field_proto) { + // Have to delay resolving of the default value until now because of the enum + // case, since enum defaults are specified with a label. + if (google_protobuf_FieldDescriptorProto_has_default_value(field_proto)) { + upb_StringView defaultval = + google_protobuf_FieldDescriptorProto_default_value(field_proto); -const google_protobuf_OneofOptions* upb_OneofDef_Options( - const upb_OneofDef* o) { - return o->opts; -} + if (upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3) { + _upb_DefBuilder_Errf(ctx, + "proto3 fields cannot have explicit defaults (%s)", + f->full_name); + } -bool upb_OneofDef_HasOptions(const upb_OneofDef* o) { - return o->opts != (void*)opt_default; -} + if (upb_FieldDef_IsSubMessage(f)) { + _upb_DefBuilder_Errf(ctx, + "message fields cannot have explicit defaults (%s)", + f->full_name); + } -const char* upb_OneofDef_Name(const upb_OneofDef* o) { - return shortdefname(o->full_name); + parse_default(ctx, defaultval.data, defaultval.size, f); + f->has_default = true; + } else { + set_default_default(ctx, f); + f->has_default = false; + } } -const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o) { - return o->parent; -} +void _upb_FieldDef_Resolve(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f) { + // We have to stash this away since resolve_subdef() may overwrite it. + const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; -int upb_OneofDef_FieldCount(const upb_OneofDef* o) { return o->field_count; } + resolve_subdef(ctx, prefix, f); + resolve_default(ctx, f, field_proto); -const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i) { - UPB_ASSERT(i < o->field_count); - return o->fields[i]; + if (f->is_extension_) { + resolve_extension(ctx, prefix, f, field_proto); + } } -int upb_OneofDef_numfields(const upb_OneofDef* o) { return o->field_count; } -uint32_t upb_OneofDef_Index(const upb_OneofDef* o) { - // Compute index in our parent's array. - return o - o->parent->oneofs; -} -bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o) { return o->synthetic; } +// Must be last. -const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, - const char* name, - size_t length) { - upb_value val; - return upb_strtable_lookup2(&o->ntof, name, length, &val) - ? upb_value_getptr(val) - : NULL; -} +struct upb_FileDef { + const google_protobuf_FileOptions* opts; + const char* name; + const char* package; -const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, - uint32_t num) { - upb_value val; - return upb_inttable_lookup(&o->itof, num, &val) ? upb_value_getptr(val) - : NULL; -} + const upb_FileDef** deps; + const int32_t* public_deps; + const int32_t* weak_deps; + const upb_MessageDef* top_lvl_msgs; + const upb_EnumDef* top_lvl_enums; + const upb_FieldDef* top_lvl_exts; + const upb_ServiceDef* services; + const upb_MiniTable_Extension** ext_layouts; + const upb_DefPool* symtab; -/* upb_FileDef ****************************************************************/ + int dep_count; + int public_dep_count; + int weak_dep_count; + int top_lvl_msg_count; + int top_lvl_enum_count; + int top_lvl_ext_count; + int service_count; + int ext_count; // All exts in the file. + upb_Syntax syntax; +}; const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f) { return f->opts; } bool upb_FileDef_HasOptions(const upb_FileDef* f) { - return f->opts != (void*)opt_default; + return f->opts != (void*)kUpbDefOptDefault; } const char* upb_FileDef_Name(const upb_FileDef* f) { return f->name; } -const char* upb_FileDef_Package(const upb_FileDef* f) { return f->package; } +const char* upb_FileDef_Package(const upb_FileDef* f) { + return f->package ? f->package : ""; +} + +const char* _upb_FileDef_RawPackage(const upb_FileDef* f) { return f->package; } upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f) { return f->syntax; } @@ -6407,4967 +8026,4942 @@ const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i) { const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i) { UPB_ASSERT(0 <= i && i < f->top_lvl_msg_count); - return &f->top_lvl_msgs[i]; + return _upb_MessageDef_At(f->top_lvl_msgs, i); } const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i) { UPB_ASSERT(0 <= i && i < f->top_lvl_enum_count); - return &f->top_lvl_enums[i]; + return _upb_EnumDef_At(f->top_lvl_enums, i); } const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i) { UPB_ASSERT(0 <= i && i < f->top_lvl_ext_count); - return &f->top_lvl_exts[i]; + return _upb_FieldDef_At(f->top_lvl_exts, i); } const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i) { UPB_ASSERT(0 <= i && i < f->service_count); - return &f->services[i]; + return _upb_ServiceDef_At(f->services, i); } const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f) { return f->symtab; } -/* upb_MethodDef **************************************************************/ - -const google_protobuf_MethodOptions* upb_MethodDef_Options( - const upb_MethodDef* m) { - return m->opts; -} - -bool upb_MethodDef_HasOptions(const upb_MethodDef* m) { - return m->opts != (void*)opt_default; -} - -const char* upb_MethodDef_FullName(const upb_MethodDef* m) { - return m->full_name; -} - -int upb_MethodDef_Index(const upb_MethodDef* m) { return m->index; } - -const char* upb_MethodDef_Name(const upb_MethodDef* m) { - return shortdefname(m->full_name); -} - -const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m) { - return m->service; -} - -const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m) { - return m->input_type; -} - -const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m) { - return m->output_type; -} - -bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m) { - return m->client_streaming; +const upb_MiniTable_Extension* _upb_FileDef_ExtensionMiniTable( + const upb_FileDef* f, int i) { + return f->ext_layouts[i]; } -bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { - return m->server_streaming; +static char* strviewdup(upb_DefBuilder* ctx, upb_StringView view) { + char* ret = upb_strdup2(view.data, view.size, _upb_DefBuilder_Arena(ctx)); + if (!ret) _upb_DefBuilder_OomErr(ctx); + return ret; } -/* upb_ServiceDef *************************************************************/ - -const google_protobuf_ServiceOptions* upb_ServiceDef_Options( - const upb_ServiceDef* s) { - return s->opts; +static bool streql_view(upb_StringView view, const char* b) { + return view.size == strlen(b) && memcmp(view.data, b, view.size) == 0; } -bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s) { - return s->opts != (void*)opt_default; -} +static int count_exts_in_msg(const google_protobuf_DescriptorProto* msg_proto) { + size_t n; + google_protobuf_DescriptorProto_extension(msg_proto, &n); + int ext_count = n; -const char* upb_ServiceDef_FullName(const upb_ServiceDef* s) { - return s->full_name; -} + const google_protobuf_DescriptorProto* const* nested_msgs = + google_protobuf_DescriptorProto_nested_type(msg_proto, &n); + for (size_t i = 0; i < n; i++) { + ext_count += count_exts_in_msg(nested_msgs[i]); + } -const char* upb_ServiceDef_Name(const upb_ServiceDef* s) { - return shortdefname(s->full_name); + return ext_count; } -int upb_ServiceDef_Index(const upb_ServiceDef* s) { return s->index; } - -const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s) { - return s->file; -} +// Allocate and initialize one file def, and add it to the context object. +void _upb_FileDef_Create(upb_DefBuilder* ctx, + const google_protobuf_FileDescriptorProto* file_proto) { + upb_FileDef* file = _upb_DefBuilder_Alloc(ctx, sizeof(upb_FileDef)); + ctx->file = file; -int upb_ServiceDef_MethodCount(const upb_ServiceDef* s) { - return s->method_count; -} + const google_protobuf_DescriptorProto* const* msgs; + const google_protobuf_EnumDescriptorProto* const* enums; + const google_protobuf_FieldDescriptorProto* const* exts; + const google_protobuf_ServiceDescriptorProto* const* services; + const upb_StringView* strs; + const int32_t* public_deps; + const int32_t* weak_deps; + size_t n; -const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i) { - return i < 0 || i >= s->method_count ? NULL : &s->methods[i]; -} + file->symtab = ctx->symtab; -const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, - const char* name) { - for (int i = 0; i < s->method_count; i++) { - if (strcmp(name, upb_MethodDef_Name(&s->methods[i])) == 0) { - return &s->methods[i]; - } + // Count all extensions in the file, to build a flat array of layouts. + google_protobuf_FileDescriptorProto_extension(file_proto, &n); + int ext_count = n; + msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); + for (int i = 0; i < n; i++) { + ext_count += count_exts_in_msg(msgs[i]); } - return NULL; -} - -/* upb_DefPool ****************************************************************/ - -void upb_DefPool_Free(upb_DefPool* s) { - upb_Arena_Free(s->arena); - upb_gfree(s); -} - -upb_DefPool* upb_DefPool_New(void) { - upb_DefPool* s = upb_gmalloc(sizeof(*s)); + file->ext_count = ext_count; - if (!s) { - return NULL; + if (ctx->layout) { + // We are using the ext layouts that were passed in. + file->ext_layouts = ctx->layout->exts; + if (ctx->layout->ext_count != file->ext_count) { + _upb_DefBuilder_Errf(ctx, + "Extension count did not match layout (%d vs %d)", + ctx->layout->ext_count, file->ext_count); + } + } else { + // We are building ext layouts from scratch. + file->ext_layouts = _upb_DefBuilder_Alloc( + ctx, sizeof(*file->ext_layouts) * file->ext_count); + upb_MiniTable_Extension* ext = + _upb_DefBuilder_Alloc(ctx, sizeof(*ext) * file->ext_count); + for (int i = 0; i < file->ext_count; i++) { + file->ext_layouts[i] = &ext[i]; + } } - s->arena = upb_Arena_New(); - s->bytes_loaded = 0; - - if (!upb_strtable_init(&s->syms, 32, s->arena) || - !upb_strtable_init(&s->files, 4, s->arena) || - !upb_inttable_init(&s->exts, s->arena)) { - goto err; + if (!google_protobuf_FileDescriptorProto_has_name(file_proto)) { + _upb_DefBuilder_Errf(ctx, "File has no name"); } - s->extreg = upb_ExtensionRegistry_New(s->arena); - if (!s->extreg) goto err; - return s; - -err: - upb_Arena_Free(s->arena); - upb_gfree(s); - return NULL; -} - -static const void* symtab_lookup(const upb_DefPool* s, const char* sym, - upb_deftype_t type) { - upb_value v; - return upb_strtable_lookup(&s->syms, sym, &v) ? unpack_def(v, type) : NULL; -} - -static const void* symtab_lookup2(const upb_DefPool* s, const char* sym, - size_t size, upb_deftype_t type) { - upb_value v; - return upb_strtable_lookup2(&s->syms, sym, size, &v) ? unpack_def(v, type) - : NULL; -} + file->name = strviewdup(ctx, google_protobuf_FileDescriptorProto_name(file_proto)); -const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, - const char* sym) { - return symtab_lookup(s, sym, UPB_DEFTYPE_MSG); -} + upb_StringView package = google_protobuf_FileDescriptorProto_package(file_proto); + if (package.size) { + _upb_DefBuilder_CheckIdentFull(ctx, package); + file->package = strviewdup(ctx, package); + } else { + file->package = NULL; + } -const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( - const upb_DefPool* s, const char* sym, size_t len) { - return symtab_lookup2(s, sym, len, UPB_DEFTYPE_MSG); -} + if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) { + upb_StringView syntax = google_protobuf_FileDescriptorProto_syntax(file_proto); -const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, - const char* sym) { - return symtab_lookup(s, sym, UPB_DEFTYPE_ENUM); -} + if (streql_view(syntax, "proto2")) { + file->syntax = kUpb_Syntax_Proto2; + } else if (streql_view(syntax, "proto3")) { + file->syntax = kUpb_Syntax_Proto3; + } else { + _upb_DefBuilder_Errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(syntax)); + } + } else { + file->syntax = kUpb_Syntax_Proto2; + } -const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, - const char* sym) { - return symtab_lookup(s, sym, UPB_DEFTYPE_ENUMVAL); -} + // Read options. + UBP_DEF_SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); -const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, - const char* name) { - upb_value v; - return upb_strtable_lookup(&s->files, name, &v) - ? unpack_def(v, UPB_DEFTYPE_FILE) - : NULL; -} + // Verify dependencies. + strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n); + file->dep_count = n; + file->deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->deps) * n); -const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, - const char* name, - size_t len) { - upb_value v; - return upb_strtable_lookup2(&s->files, name, len, &v) - ? unpack_def(v, UPB_DEFTYPE_FILE) - : NULL; -} + for (size_t i = 0; i < n; i++) { + upb_StringView str = strs[i]; + file->deps[i] = + upb_DefPool_FindFileByNameWithSize(ctx->symtab, str.data, str.size); + if (!file->deps[i]) { + _upb_DefBuilder_Errf(ctx, + "Depends on file '" UPB_STRINGVIEW_FORMAT + "', but it has not been loaded", + UPB_STRINGVIEW_ARGS(str)); + } + } -const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( - const upb_DefPool* s, const char* name, size_t size) { - upb_value v; - if (!upb_strtable_lookup2(&s->syms, name, size, &v)) return NULL; + public_deps = google_protobuf_FileDescriptorProto_public_dependency(file_proto, &n); + file->public_dep_count = n; + file->public_deps = + _upb_DefBuilder_Alloc(ctx, sizeof(*file->public_deps) * n); + int32_t* mutable_public_deps = (int32_t*)file->public_deps; + for (size_t i = 0; i < n; i++) { + if (public_deps[i] >= file->dep_count) { + _upb_DefBuilder_Errf(ctx, "public_dep %d is out of range", + (int)public_deps[i]); + } + mutable_public_deps[i] = public_deps[i]; + } - switch (deftype(v)) { - case UPB_DEFTYPE_FIELD: - return unpack_def(v, UPB_DEFTYPE_FIELD); - case UPB_DEFTYPE_MSG: { - const upb_MessageDef* m = unpack_def(v, UPB_DEFTYPE_MSG); - return m->in_message_set ? &m->nested_exts[0] : NULL; + weak_deps = google_protobuf_FileDescriptorProto_weak_dependency(file_proto, &n); + file->weak_dep_count = n; + file->weak_deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->weak_deps) * n); + int32_t* mutable_weak_deps = (int32_t*)file->weak_deps; + for (size_t i = 0; i < n; i++) { + if (weak_deps[i] >= file->dep_count) { + _upb_DefBuilder_Errf(ctx, "weak_dep %d is out of range", + (int)weak_deps[i]); } - default: - break; + mutable_weak_deps[i] = weak_deps[i]; } - return NULL; -} + // Create enums. + enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); + file->top_lvl_enum_count = n; + file->top_lvl_enums = _upb_EnumDefs_New(ctx, n, enums, NULL); -const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, - const char* sym) { - return upb_DefPool_FindExtensionByNameWithSize(s, sym, strlen(sym)); -} + // Create extensions. + exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n); + file->top_lvl_ext_count = n; + file->top_lvl_exts = + _upb_FieldDefs_New(ctx, n, exts, file->package, NULL, NULL); -const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, - const char* name) { - return symtab_lookup(s, name, UPB_DEFTYPE_SERVICE); -} + // Create messages. + msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); + file->top_lvl_msg_count = n; + file->top_lvl_msgs = _upb_MessageDefs_New(ctx, n, msgs, NULL); -const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( - const upb_DefPool* s, const char* name, size_t size) { - return symtab_lookup2(s, name, size, UPB_DEFTYPE_SERVICE); -} + // Create services. + services = google_protobuf_FileDescriptorProto_service(file_proto, &n); + file->service_count = n; + file->services = _upb_ServiceDefs_New(ctx, n, services); -const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, - const char* name) { - upb_value v; - // TODO(haberman): non-extension fields and oneofs. - if (upb_strtable_lookup(&s->syms, name, &v)) { - switch (deftype(v)) { - case UPB_DEFTYPE_EXT: { - const upb_FieldDef* f = unpack_def(v, UPB_DEFTYPE_EXT); - return upb_FieldDef_File(f); - } - case UPB_DEFTYPE_MSG: { - const upb_MessageDef* m = unpack_def(v, UPB_DEFTYPE_MSG); - return upb_MessageDef_File(m); - } - case UPB_DEFTYPE_ENUM: { - const upb_EnumDef* e = unpack_def(v, UPB_DEFTYPE_ENUM); - return upb_EnumDef_File(e); - } - case UPB_DEFTYPE_ENUMVAL: { - const upb_EnumValueDef* ev = unpack_def(v, UPB_DEFTYPE_ENUMVAL); - return upb_EnumDef_File(upb_EnumValueDef_Enum(ev)); - } - case UPB_DEFTYPE_SERVICE: { - const upb_ServiceDef* service = unpack_def(v, UPB_DEFTYPE_SERVICE); - return upb_ServiceDef_File(service); - } - default: - UPB_UNREACHABLE(); - } + // Now that all names are in the table, build layouts and resolve refs. + + for (int i = 0; i < file->top_lvl_msg_count; i++) { + upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); + _upb_MessageDef_Resolve(ctx, m); } - const char* last_dot = strrchr(name, '.'); - if (last_dot) { - const upb_MessageDef* parent = - upb_DefPool_FindMessageByNameWithSize(s, name, last_dot - name); - if (parent) { - const char* shortname = last_dot + 1; - if (upb_MessageDef_FindByNameWithSize(parent, shortname, - strlen(shortname), NULL, NULL)) { - return upb_MessageDef_File(parent); - } + for (int i = 0; i < file->top_lvl_ext_count; i++) { + upb_FieldDef* f = (upb_FieldDef*)upb_FileDef_TopLevelExtension(file, i); + _upb_FieldDef_Resolve(ctx, file->package, f); + } + + if (!ctx->layout) { + for (int i = 0; i < file->top_lvl_msg_count; i++) { + upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); + _upb_MessageDef_LinkMiniTable(ctx, m); } } - return NULL; + if (file->ext_count) { + bool ok = _upb_extreg_add(_upb_DefPool_ExtReg(ctx->symtab), + file->ext_layouts, file->ext_count); + if (!ok) _upb_DefBuilder_OomErr(ctx); + } } -/* Code to build defs from descriptor protos. *********************************/ -/* There is a question of how much validation to do here. It will be difficult - * to perfectly match the amount of validation performed by proto2. But since - * this code is used to directly build defs from Ruby (for example) we do need - * to validate important constraints like uniqueness of names and numbers. */ +#include -#define CHK_OOM(x) \ - if (!(x)) { \ - symtab_oomerr(ctx); \ - } -typedef struct { - upb_DefPool* symtab; - upb_FileDef* file; /* File we are building. */ - upb_Arena* arena; /* Allocate defs here. */ - upb_Arena* tmp_arena; /* For temporary allocations. */ - const upb_MiniTable_File* layout; /* NULL if we should build layouts. */ - int enum_count; /* Count of enums built so far. */ - int msg_count; /* Count of messages built so far. */ - int ext_count; /* Count of extensions built so far. */ - upb_Status* status; /* Record errors here. */ - jmp_buf err; /* longjmp() on error. */ -} symtab_addctx; - -UPB_NORETURN UPB_NOINLINE UPB_PRINTF(2, 3) static void symtab_errf( - symtab_addctx* ctx, const char* fmt, ...) { - va_list argp; - va_start(argp, fmt); - upb_Status_VSetErrorFormat(ctx->status, fmt, argp); - va_end(argp); - UPB_LONGJMP(ctx->err, 1); +// Must be last. + +static size_t get_field_size(const upb_MiniTable_Field* f) { + static unsigned char sizes[] = { + 0, /* 0 */ + 8, /* kUpb_FieldType_Double */ + 4, /* kUpb_FieldType_Float */ + 8, /* kUpb_FieldType_Int64 */ + 8, /* kUpb_FieldType_UInt64 */ + 4, /* kUpb_FieldType_Int32 */ + 8, /* kUpb_FieldType_Fixed64 */ + 4, /* kUpb_FieldType_Fixed32 */ + 1, /* kUpb_FieldType_Bool */ + sizeof(upb_StringView), /* kUpb_FieldType_String */ + sizeof(void*), /* kUpb_FieldType_Group */ + sizeof(void*), /* kUpb_FieldType_Message */ + sizeof(upb_StringView), /* kUpb_FieldType_Bytes */ + 4, /* kUpb_FieldType_UInt32 */ + 4, /* kUpb_FieldType_Enum */ + 4, /* kUpb_FieldType_SFixed32 */ + 8, /* kUpb_FieldType_SFixed64 */ + 4, /* kUpb_FieldType_SInt32 */ + 8, /* kUpb_FieldType_SInt64 */ + }; + return upb_IsRepeatedOrMap(f) ? sizeof(void*) : sizes[f->descriptortype]; } -UPB_NORETURN UPB_NOINLINE static void symtab_oomerr(symtab_addctx* ctx) { - upb_Status_setoom(ctx->status); - UPB_LONGJMP(ctx->err, 1); +upb_Message* upb_Message_New(const upb_MessageDef* m, upb_Arena* a) { + return _upb_Message_New(upb_MessageDef_MiniTable(m), a); } -void* symtab_alloc(symtab_addctx* ctx, size_t bytes) { - if (bytes == 0) return NULL; - void* ret = upb_Arena_Malloc(ctx->arena, bytes); - if (!ret) symtab_oomerr(ctx); - return ret; +static bool in_oneof(const upb_MiniTable_Field* field) { + return field->presence < 0; } -// We want to copy the options verbatim into the destination options proto. -// We use serialize+parse as our deep copy. -#define SET_OPTIONS(target, desc_type, options_type, proto) \ - if (google_protobuf_##desc_type##_has_options(proto)) { \ - size_t size; \ - char* pb = google_protobuf_##options_type##_serialize( \ - google_protobuf_##desc_type##_options(proto), ctx->tmp_arena, &size); \ - CHK_OOM(pb); \ - target = google_protobuf_##options_type##_parse(pb, size, ctx->arena); \ - CHK_OOM(target); \ - } else { \ - target = (const google_protobuf_##options_type*)opt_default; \ - } +static upb_MessageValue _upb_Message_Getraw(const upb_Message* msg, + const upb_FieldDef* f) { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); + const char* mem = UPB_PTR_AT(msg, field->offset, char); + upb_MessageValue val = {0}; + memcpy(&val, mem, get_field_size(field)); + return val; +} -static void check_ident(symtab_addctx* ctx, upb_StringView name, bool full) { - const char* str = name.data; - size_t len = name.size; - bool start = true; - size_t i; - for (i = 0; i < len; i++) { - char c = str[i]; - if (c == '.') { - if (start || !full) { - symtab_errf(ctx, "invalid name: unexpected '.' (%.*s)", (int)len, str); - } - start = true; - } else if (start) { - if (!upb_isletter(c)) { - symtab_errf( - ctx, - "invalid name: path components must start with a letter (%.*s)", - (int)len, str); - } - start = false; +bool upb_Message_Has(const upb_Message* msg, const upb_FieldDef* f) { + assert(upb_FieldDef_HasPresence(f)); + if (upb_FieldDef_IsExtension(f)) { + const upb_MiniTable_Extension* ext = _upb_FieldDef_ExtensionMiniTable(f); + return _upb_Message_Getext(msg, ext) != NULL; + } else { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); + if (in_oneof(field)) { + return _upb_getoneofcase_field(msg, field) == field->number; + } else if (field->presence > 0) { + return _upb_hasbit_field(msg, field); } else { - if (!upb_isalphanum(c)) { - symtab_errf(ctx, "invalid name: non-alphanumeric character (%.*s)", - (int)len, str); - } + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message || + field->descriptortype == kUpb_FieldType_Group); + return _upb_Message_Getraw(msg, f).msg_val != NULL; } } - if (start) { - symtab_errf(ctx, "invalid name: empty part (%.*s)", (int)len, str); - } } -static size_t div_round_up(size_t n, size_t d) { return (n + d - 1) / d; } +const upb_FieldDef* upb_Message_WhichOneof(const upb_Message* msg, + const upb_OneofDef* o) { + const upb_FieldDef* f = upb_OneofDef_Field(o, 0); + if (upb_OneofDef_IsSynthetic(o)) { + UPB_ASSERT(upb_OneofDef_FieldCount(o) == 1); + return upb_Message_Has(msg, f) ? f : NULL; + } else { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); + uint32_t oneof_case = _upb_getoneofcase_field(msg, field); + f = oneof_case ? upb_OneofDef_LookupNumber(o, oneof_case) : NULL; + UPB_ASSERT((f != NULL) == (oneof_case != 0)); + return f; + } +} -static size_t upb_MessageValue_sizeof(upb_CType type) { - switch (type) { - case kUpb_CType_Double: - case kUpb_CType_Int64: - case kUpb_CType_UInt64: - return 8; - case kUpb_CType_Enum: - case kUpb_CType_Int32: - case kUpb_CType_UInt32: - case kUpb_CType_Float: - return 4; - case kUpb_CType_Bool: - return 1; - case kUpb_CType_Message: - return sizeof(void*); - case kUpb_CType_Bytes: - case kUpb_CType_String: - return sizeof(upb_StringView); +upb_MessageValue upb_Message_Get(const upb_Message* msg, + const upb_FieldDef* f) { + if (upb_FieldDef_IsExtension(f)) { + const upb_Message_Extension* ext = + _upb_Message_Getext(msg, _upb_FieldDef_ExtensionMiniTable(f)); + if (ext) { + upb_MessageValue val; + memcpy(&val, &ext->data, sizeof(val)); + return val; + } else if (upb_FieldDef_IsRepeated(f)) { + return (upb_MessageValue){.array_val = NULL}; + } + } else if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) { + return _upb_Message_Getraw(msg, f); } - UPB_UNREACHABLE(); + return upb_FieldDef_Default(f); } -static uint8_t upb_msg_fielddefsize(const upb_FieldDef* f) { - if (upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f))) { - upb_MapEntry ent; - UPB_ASSERT(sizeof(ent.k) == sizeof(ent.v)); - return sizeof(ent.k); +upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, + const upb_FieldDef* f, + upb_Arena* a) { + UPB_ASSERT(upb_FieldDef_IsSubMessage(f) || upb_FieldDef_IsRepeated(f)); + if (upb_FieldDef_HasPresence(f) && !upb_Message_Has(msg, f)) { + // We need to skip the upb_Message_Get() call in this case. + goto make; + } + + upb_MessageValue val = upb_Message_Get(msg, f); + if (val.array_val) { + return (upb_MutableMessageValue){.array = (upb_Array*)val.array_val}; + } + + upb_MutableMessageValue ret; +make: + if (!a) return (upb_MutableMessageValue){.array = NULL}; + if (upb_FieldDef_IsMap(f)) { + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key = + upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_KeyFieldNumber); + const upb_FieldDef* value = + upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_ValueFieldNumber); + ret.map = + upb_Map_New(a, upb_FieldDef_CType(key), upb_FieldDef_CType(value)); } else if (upb_FieldDef_IsRepeated(f)) { - return sizeof(void*); + ret.array = upb_Array_New(a, upb_FieldDef_CType(f)); } else { - return upb_MessageValue_sizeof(upb_FieldDef_CType(f)); + UPB_ASSERT(upb_FieldDef_IsSubMessage(f)); + ret.msg = upb_Message_New(upb_FieldDef_MessageSubDef(f), a); } -} -static uint32_t upb_MiniTable_place(symtab_addctx* ctx, upb_MiniTable* l, - size_t size, const upb_MessageDef* m) { - size_t ofs = UPB_ALIGN_UP(l->size, size); - size_t next = ofs + size; - - if (next > UINT16_MAX) { - symtab_errf(ctx, "size of message %s exceeded max size of %zu bytes", - upb_MessageDef_FullName(m), (size_t)UINT16_MAX); - } + val.array_val = ret.array; + upb_Message_Set(msg, f, val, a); - l->size = next; - return ofs; + return ret; } -static int field_number_cmp(const void* p1, const void* p2) { - const upb_MiniTable_Field* f1 = p1; - const upb_MiniTable_Field* f2 = p2; - return f1->number - f2->number; -} +bool upb_Message_Set(upb_Message* msg, const upb_FieldDef* f, + upb_MessageValue val, upb_Arena* a) { + if (upb_FieldDef_IsExtension(f)) { + upb_Message_Extension* ext = _upb_Message_GetOrCreateExtension( + msg, _upb_FieldDef_ExtensionMiniTable(f), a); + if (!ext) return false; + memcpy(&ext->data, &val, sizeof(val)); + } else { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); -static void assign_layout_indices(const upb_MessageDef* m, upb_MiniTable* l, - upb_MiniTable_Field* fields) { - int i; - int n = upb_MessageDef_numfields(m); - int dense_below = 0; - for (i = 0; i < n; i++) { - upb_FieldDef* f = - (upb_FieldDef*)upb_MessageDef_FindFieldByNumber(m, fields[i].number); - UPB_ASSERT(f); - f->layout_index = i; - if (i < UINT8_MAX && fields[i].number == i + 1 && - (i == 0 || fields[i - 1].number == i)) { - dense_below = i + 1; + // Building reflection should always cause all sub-message types to be + // linked, but double-check here just for extra assurance. + UPB_ASSERT(!upb_FieldDef_IsSubMessage(f) || + upb_MessageDef_MiniTable(upb_FieldDef_ContainingType(f)) + ->subs[field->submsg_index] + .submsg); + + char* mem = UPB_PTR_AT(msg, field->offset, char); + memcpy(mem, &val, get_field_size(field)); + if (field->presence > 0) { + _upb_sethas_field(msg, field); + } else if (in_oneof(field)) { + *_upb_oneofcase_field(msg, field) = field->number; } } - l->dense_below = dense_below; + return true; } -static uint8_t map_descriptortype(const upb_FieldDef* f) { - uint8_t type = upb_FieldDef_Type(f); - /* See TableDescriptorType() in upbc/generator.cc for details and - * rationale of these exceptions. */ - if (type == kUpb_FieldType_String && f->file->syntax == kUpb_Syntax_Proto2) { - return kUpb_FieldType_Bytes; - } else if (type == kUpb_FieldType_Enum && - f->sub.enumdef->file->syntax == kUpb_Syntax_Proto3) { - return kUpb_FieldType_Int32; - } - return type; -} +void upb_Message_ClearField(upb_Message* msg, const upb_FieldDef* f) { + if (upb_FieldDef_IsExtension(f)) { + _upb_Message_Clearext(msg, _upb_FieldDef_ExtensionMiniTable(f)); + } else { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); + char* mem = UPB_PTR_AT(msg, field->offset, char); -static void fill_fieldlayout(upb_MiniTable_Field* field, - const upb_FieldDef* f) { - field->number = upb_FieldDef_Number(f); - field->descriptortype = map_descriptortype(f); + if (field->presence > 0) { + _upb_clearhas_field(msg, field); + } else if (in_oneof(field)) { + uint32_t* oneof_case = _upb_oneofcase_field(msg, field); + if (*oneof_case != field->number) return; + *oneof_case = 0; + } - if (upb_FieldDef_IsMap(f)) { - field->mode = - kUpb_FieldMode_Map | (upb_FieldRep_Pointer << upb_FieldRep_Shift); - } else if (upb_FieldDef_IsRepeated(f)) { - field->mode = - kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift); - } else { - /* Maps descriptor type -> elem_size_lg2. */ - static const uint8_t sizes[] = { - -1, /* invalid descriptor type */ - upb_FieldRep_8Byte, /* DOUBLE */ - upb_FieldRep_4Byte, /* FLOAT */ - upb_FieldRep_8Byte, /* INT64 */ - upb_FieldRep_8Byte, /* UINT64 */ - upb_FieldRep_4Byte, /* INT32 */ - upb_FieldRep_8Byte, /* FIXED64 */ - upb_FieldRep_4Byte, /* FIXED32 */ - upb_FieldRep_1Byte, /* BOOL */ - upb_FieldRep_StringView, /* STRING */ - upb_FieldRep_Pointer, /* GROUP */ - upb_FieldRep_Pointer, /* MESSAGE */ - upb_FieldRep_StringView, /* BYTES */ - upb_FieldRep_4Byte, /* UINT32 */ - upb_FieldRep_4Byte, /* ENUM */ - upb_FieldRep_4Byte, /* SFIXED32 */ - upb_FieldRep_8Byte, /* SFIXED64 */ - upb_FieldRep_4Byte, /* SINT32 */ - upb_FieldRep_8Byte, /* SINT64 */ - }; - field->mode = kUpb_FieldMode_Scalar | - (sizes[field->descriptortype] << upb_FieldRep_Shift); - } - - if (upb_FieldDef_IsPacked(f)) { - field->mode |= upb_LabelFlags_IsPacked; + memset(mem, 0, get_field_size(field)); } +} - if (upb_FieldDef_IsExtension(f)) { - field->mode |= upb_LabelFlags_IsExtension; - } +void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m) { + _upb_Message_Clear(msg, upb_MessageDef_MiniTable(m)); } -/* This function is the dynamic equivalent of message_layout.{cc,h} in upbc. - * It computes a dynamic layout for all of the fields in |m|. */ -static void make_layout(symtab_addctx* ctx, const upb_MessageDef* m) { - upb_MiniTable* l = (upb_MiniTable*)m->layout; - size_t field_count = upb_MessageDef_numfields(m); - size_t sublayout_count = 0; - upb_MiniTable_Sub* subs; - upb_MiniTable_Field* fields; +bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, const upb_FieldDef** out_f, + upb_MessageValue* out_val, size_t* iter) { + size_t i = *iter; + size_t n = upb_MessageDef_FieldCount(m); + const upb_MessageValue zero = {0}; + UPB_UNUSED(ext_pool); - memset(l, 0, sizeof(*l) + sizeof(_upb_FastTable_Entry)); + /* Iterate over normal fields, returning the first one that is set. */ + while (++i < n) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + upb_MessageValue val = _upb_Message_Getraw(msg, f); - /* Count sub-messages. */ - for (size_t i = 0; i < field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - if (upb_FieldDef_IsSubMessage(f)) { - sublayout_count++; - } - if (upb_FieldDef_CType(f) == kUpb_CType_Enum && - f->sub.enumdef->file->syntax == kUpb_Syntax_Proto2) { - sublayout_count++; - } - } + /* Skip field if unset or empty. */ + if (upb_FieldDef_HasPresence(f)) { + if (!upb_Message_Has(msg, f)) continue; + } else { + upb_MessageValue test = val; + if (upb_FieldDef_IsString(f) && !upb_FieldDef_IsRepeated(f)) { + /* Clear string pointer, only size matters (ptr could be non-NULL). */ + test.str_val.data = NULL; + } + /* Continue if NULL or 0. */ + if (memcmp(&test, &zero, sizeof(test)) == 0) continue; - fields = symtab_alloc(ctx, field_count * sizeof(*fields)); - subs = symtab_alloc(ctx, sublayout_count * sizeof(*subs)); + /* Continue on empty array or map. */ + if (upb_FieldDef_IsMap(f)) { + if (upb_Map_Size(test.map_val) == 0) continue; + } else if (upb_FieldDef_IsRepeated(f)) { + if (upb_Array_Size(test.array_val) == 0) continue; + } + } - l->field_count = upb_MessageDef_numfields(m); - l->fields = fields; - l->subs = subs; - l->table_mask = 0; - l->required_count = 0; + *out_val = val; + *out_f = f; + *iter = i; + return true; + } - if (upb_MessageDef_ExtensionRangeCount(m) > 0) { - if (google_protobuf_MessageOptions_message_set_wire_format(m->opts)) { - l->ext = upb_ExtMode_IsMessageSet; - } else { - l->ext = upb_ExtMode_Extendable; + if (ext_pool) { + /* Return any extensions that are set. */ + size_t count; + const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &count); + if (i - n < count) { + ext += count - 1 - (i - n); + memcpy(out_val, &ext->data, sizeof(*out_val)); + *out_f = _upb_DefPool_FindExtensionByMiniTable(ext_pool, ext->ext); + *iter = i; + return true; } - } else { - l->ext = upb_ExtMode_NonExtendable; } - /* TODO(haberman): initialize fast tables so that reflection-based parsing - * can get the same speeds as linked-in types. */ - l->fasttable[0].field_parser = &fastdecode_generic; - l->fasttable[0].field_data = 0; - - if (upb_MessageDef_IsMapEntry(m)) { - /* TODO(haberman): refactor this method so this special case is more - * elegant. */ - const upb_FieldDef* key = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_FieldDef* val = upb_MessageDef_FindFieldByNumber(m, 2); - fields[0].number = 1; - fields[1].number = 2; - fields[0].mode = kUpb_FieldMode_Scalar; - fields[1].mode = kUpb_FieldMode_Scalar; - fields[0].presence = 0; - fields[1].presence = 0; - fields[0].descriptortype = map_descriptortype(key); - fields[1].descriptortype = map_descriptortype(val); - fields[0].offset = 0; - fields[1].offset = sizeof(upb_StringView); - fields[1].submsg_index = 0; - - if (upb_FieldDef_CType(val) == kUpb_CType_Message) { - subs[0].submsg = upb_FieldDef_MessageSubDef(val)->layout; - } - - upb_FieldDef* fielddefs = (upb_FieldDef*)&m->fields[0]; - UPB_ASSERT(fielddefs[0].number_ == 1); - UPB_ASSERT(fielddefs[1].number_ == 2); - fielddefs[0].layout_index = 0; - fielddefs[1].layout_index = 1; - - l->field_count = 2; - l->size = 2 * sizeof(upb_StringView); - l->size = UPB_ALIGN_UP(l->size, 8); - l->dense_below = 2; - return; - } + *iter = i; + return false; +} - /* Allocate data offsets in three stages: - * - * 1. hasbits. - * 2. regular fields. - * 3. oneof fields. - * - * OPT: There is a lot of room for optimization here to minimize the size. - */ +bool _upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, + int depth) { + size_t iter = kUpb_Message_Begin; + const upb_FieldDef* f; + upb_MessageValue val; + bool ret = true; - /* Assign hasbits for required fields first. */ - size_t hasbit = 0; + if (--depth == 0) return false; - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)]; - if (upb_FieldDef_Label(f) == kUpb_Label_Required) { - field->presence = ++hasbit; - if (hasbit >= 63) { - symtab_errf(ctx, "Message with >=63 required fields: %s", - upb_MessageDef_FullName(m)); - } - l->required_count++; - } - } + _upb_Message_DiscardUnknown_shallow(msg); - /* Allocate hasbits and set basic field attributes. */ - sublayout_count = 0; - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)]; + while (upb_Message_Next(msg, m, NULL /*ext_pool*/, &f, &val, &iter)) { + const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); + if (!subm) continue; + if (upb_FieldDef_IsMap(f)) { + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(subm, 2); + const upb_MessageDef* val_m = upb_FieldDef_MessageSubDef(val_f); + upb_Map* map = (upb_Map*)val.map_val; + size_t iter = kUpb_Map_Begin; - fill_fieldlayout(field, f); + if (!val_m) continue; - if (upb_FieldDef_IsSubMessage(f)) { - field->submsg_index = sublayout_count++; - subs[field->submsg_index].submsg = upb_FieldDef_MessageSubDef(f)->layout; - } else if (upb_FieldDef_CType(f) == kUpb_CType_Enum && - f->sub.enumdef->file->syntax == kUpb_Syntax_Proto2) { - field->submsg_index = sublayout_count++; - subs[field->submsg_index].subenum = upb_FieldDef_EnumSubDef(f)->layout; - UPB_ASSERT(subs[field->submsg_index].subenum); - } - - if (upb_FieldDef_Label(f) == kUpb_Label_Required) { - /* Hasbit was already assigned. */ - } else if (upb_FieldDef_HasPresence(f) && - !upb_FieldDef_RealContainingOneof(f)) { - /* We don't use hasbit 0, so that 0 can indicate "no presence" in the - * table. This wastes one hasbit, but we don't worry about it for now. */ - field->presence = ++hasbit; + while (upb_MapIterator_Next(map, &iter)) { + upb_MessageValue map_val = upb_MapIterator_Value(map, iter); + if (!_upb_Message_DiscardUnknown((upb_Message*)map_val.msg_val, val_m, + depth)) { + ret = false; + } + } + } else if (upb_FieldDef_IsRepeated(f)) { + const upb_Array* arr = val.array_val; + size_t i, n = upb_Array_Size(arr); + for (i = 0; i < n; i++) { + upb_MessageValue elem = upb_Array_Get(arr, i); + if (!_upb_Message_DiscardUnknown((upb_Message*)elem.msg_val, subm, + depth)) { + ret = false; + } + } } else { - field->presence = 0; + if (!_upb_Message_DiscardUnknown((upb_Message*)val.msg_val, subm, + depth)) { + ret = false; + } } } - /* Account for space used by hasbits. */ - l->size = hasbit ? div_round_up(hasbit + 1, 8) : 0; - - /* Allocate non-oneof fields. */ - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - size_t field_size = upb_msg_fielddefsize(f); - size_t index = upb_FieldDef_Index(f); + return ret; +} - if (upb_FieldDef_RealContainingOneof(f)) { - /* Oneofs are handled separately below. */ - continue; - } +bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, + int maxdepth) { + return _upb_Message_DiscardUnknown(msg, m, maxdepth); +} - fields[index].offset = upb_MiniTable_place(ctx, l, field_size, m); - } - /* Allocate oneof fields. Each oneof field consists of a uint32 for the case - * and space for the actual data. */ - for (int i = 0; i < m->oneof_count; i++) { - const upb_OneofDef* o = &m->oneofs[i]; - size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */ - size_t field_size = 0; - uint32_t case_offset; - uint32_t data_offset; - if (upb_OneofDef_IsSynthetic(o)) continue; +// Must be last. - if (o->field_count == 0) { - symtab_errf(ctx, "Oneof must have at least one field (%s)", o->full_name); - } +struct upb_MessageDef { + const google_protobuf_MessageOptions* opts; + const upb_MiniTable* layout; + const upb_FileDef* file; + const upb_MessageDef* containing_type; + const char* full_name; - /* Calculate field size: the max of all field sizes. */ - for (int j = 0; j < o->field_count; j++) { - const upb_FieldDef* f = o->fields[j]; - field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f)); - } + // Tables for looking up fields by number and name. + upb_inttable itof; + upb_strtable ntof; - /* Align and allocate case offset. */ - case_offset = upb_MiniTable_place(ctx, l, case_size, m); - data_offset = upb_MiniTable_place(ctx, l, field_size, m); + /* All nested defs. + * MEM: We could save some space here by putting nested defs in a contiguous + * region and calculating counts from offsets or vice-versa. */ + const upb_FieldDef* fields; + const upb_OneofDef* oneofs; + const upb_ExtensionRange* ext_ranges; + const upb_MessageDef* nested_msgs; + const upb_EnumDef* nested_enums; + const upb_FieldDef* nested_exts; + int field_count; + int real_oneof_count; + int oneof_count; + int ext_range_count; + int nested_msg_count; + int nested_enum_count; + int nested_ext_count; + bool in_message_set; + bool is_sorted; + upb_WellKnown well_known_type; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif +}; - for (int i = 0; i < o->field_count; i++) { - const upb_FieldDef* f = o->fields[i]; - fields[upb_FieldDef_Index(f)].offset = data_offset; - fields[upb_FieldDef_Index(f)].presence = ~case_offset; - } +static void assign_msg_wellknowntype(upb_MessageDef* m) { + const char* name = upb_MessageDef_FullName(m); + if (name == NULL) { + m->well_known_type = kUpb_WellKnown_Unspecified; + return; + } + if (!strcmp(name, "google.protobuf.Any")) { + m->well_known_type = kUpb_WellKnown_Any; + } else if (!strcmp(name, "google.protobuf.FieldMask")) { + m->well_known_type = kUpb_WellKnown_FieldMask; + } else if (!strcmp(name, "google.protobuf.Duration")) { + m->well_known_type = kUpb_WellKnown_Duration; + } else if (!strcmp(name, "google.protobuf.Timestamp")) { + m->well_known_type = kUpb_WellKnown_Timestamp; + } else if (!strcmp(name, "google.protobuf.DoubleValue")) { + m->well_known_type = kUpb_WellKnown_DoubleValue; + } else if (!strcmp(name, "google.protobuf.FloatValue")) { + m->well_known_type = kUpb_WellKnown_FloatValue; + } else if (!strcmp(name, "google.protobuf.Int64Value")) { + m->well_known_type = kUpb_WellKnown_Int64Value; + } else if (!strcmp(name, "google.protobuf.UInt64Value")) { + m->well_known_type = kUpb_WellKnown_UInt64Value; + } else if (!strcmp(name, "google.protobuf.Int32Value")) { + m->well_known_type = kUpb_WellKnown_Int32Value; + } else if (!strcmp(name, "google.protobuf.UInt32Value")) { + m->well_known_type = kUpb_WellKnown_UInt32Value; + } else if (!strcmp(name, "google.protobuf.BoolValue")) { + m->well_known_type = kUpb_WellKnown_BoolValue; + } else if (!strcmp(name, "google.protobuf.StringValue")) { + m->well_known_type = kUpb_WellKnown_StringValue; + } else if (!strcmp(name, "google.protobuf.BytesValue")) { + m->well_known_type = kUpb_WellKnown_BytesValue; + } else if (!strcmp(name, "google.protobuf.Value")) { + m->well_known_type = kUpb_WellKnown_Value; + } else if (!strcmp(name, "google.protobuf.ListValue")) { + m->well_known_type = kUpb_WellKnown_ListValue; + } else if (!strcmp(name, "google.protobuf.Struct")) { + m->well_known_type = kUpb_WellKnown_Struct; + } else { + m->well_known_type = kUpb_WellKnown_Unspecified; } +} - /* Size of the entire structure should be a multiple of its greatest - * alignment. TODO: track overall alignment for real? */ - l->size = UPB_ALIGN_UP(l->size, 8); +upb_MessageDef* _upb_MessageDef_At(const upb_MessageDef* m, int i) { + return (upb_MessageDef*)&m[i]; +} - /* Sort fields by number. */ - if (fields) { - qsort(fields, upb_MessageDef_numfields(m), sizeof(*fields), - field_number_cmp); +bool _upb_MessageDef_IsValidExtensionNumber(const upb_MessageDef* m, int n) { + for (int i = 0; i < m->ext_range_count; i++) { + const upb_ExtensionRange* r = upb_MessageDef_ExtensionRange(m, i); + if (upb_ExtensionRange_Start(r) <= n && n < upb_ExtensionRange_End(r)) { + return true; + } } - assign_layout_indices(m, l, fields); + return false; } -static char* strviewdup(symtab_addctx* ctx, upb_StringView view) { - char* ret = upb_strdup2(view.data, view.size, ctx->arena); - CHK_OOM(ret); - return ret; +const google_protobuf_MessageOptions* upb_MessageDef_Options( + const upb_MessageDef* m) { + return m->opts; } -static bool streql2(const char* a, size_t n, const char* b) { - return n == strlen(b) && memcmp(a, b, n) == 0; +bool upb_MessageDef_HasOptions(const upb_MessageDef* m) { + return m->opts != (void*)kUpbDefOptDefault; } -static bool streql_view(upb_StringView view, const char* b) { - return streql2(view.data, view.size, b); +const char* upb_MessageDef_FullName(const upb_MessageDef* m) { + return m->full_name; } -static const char* makefullname(symtab_addctx* ctx, const char* prefix, - upb_StringView name) { - if (prefix) { - /* ret = prefix + '.' + name; */ - size_t n = strlen(prefix); - char* ret = symtab_alloc(ctx, n + name.size + 2); - strcpy(ret, prefix); - ret[n] = '.'; - memcpy(&ret[n + 1], name.data, name.size); - ret[n + 1 + name.size] = '\0'; - return ret; - } else { - return strviewdup(ctx, name); - } +const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m) { + return m->file; } -static void finalize_oneofs(symtab_addctx* ctx, upb_MessageDef* m) { - int i; - int synthetic_count = 0; - upb_OneofDef* mutable_oneofs = (upb_OneofDef*)m->oneofs; +const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m) { + return m->containing_type; +} - for (i = 0; i < m->oneof_count; i++) { - upb_OneofDef* o = &mutable_oneofs[i]; +const char* upb_MessageDef_Name(const upb_MessageDef* m) { + return _upb_DefBuilder_FullToShort(m->full_name); +} - if (o->synthetic && o->field_count != 1) { - symtab_errf(ctx, "Synthetic oneofs must have one field, not %d: %s", - o->field_count, upb_OneofDef_Name(o)); - } +upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m) { + return upb_FileDef_Syntax(m->file); +} - if (o->synthetic) { - synthetic_count++; - } else if (synthetic_count != 0) { - symtab_errf(ctx, "Synthetic oneofs must be after all other oneofs: %s", - upb_OneofDef_Name(o)); - } +const upb_FieldDef* upb_MessageDef_FindFieldByNumber(const upb_MessageDef* m, + uint32_t i) { + upb_value val; + return upb_inttable_lookup(&m->itof, i, &val) ? upb_value_getconstptr(val) + : NULL; +} - o->fields = symtab_alloc(ctx, sizeof(upb_FieldDef*) * o->field_count); - o->field_count = 0; - } +const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; - for (i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - upb_OneofDef* o = (upb_OneofDef*)upb_FieldDef_ContainingOneof(f); - if (o) { - o->fields[o->field_count++] = f; - } + if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; } - m->real_oneof_count = m->oneof_count - synthetic_count; + return _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); } -size_t getjsonname(const char* name, char* buf, size_t len) { - size_t src, dst = 0; - bool ucase_next = false; - -#define WRITE(byte) \ - ++dst; \ - if (dst < len) \ - buf[dst - 1] = byte; \ - else if (dst == len) \ - buf[dst - 1] = '\0' - - if (!name) { - WRITE('\0'); - return 0; - } - - /* Implement the transformation as described in the spec: - * 1. upper case all letters after an underscore. - * 2. remove all underscores. - */ - for (src = 0; name[src]; src++) { - if (name[src] == '_') { - ucase_next = true; - continue; - } +const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; - if (ucase_next) { - WRITE(toupper(name[src])); - ucase_next = false; - } else { - WRITE(name[src]); - } + if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; } - WRITE('\0'); - return dst; - -#undef WRITE + return _upb_DefType_Unpack(val, UPB_DEFTYPE_ONEOF); } -static char* makejsonname(symtab_addctx* ctx, const char* name) { - size_t size = getjsonname(name, NULL, 0); - char* json_name = symtab_alloc(ctx, size); - getjsonname(name, json_name, size); - return json_name; +bool _upb_MessageDef_Insert(upb_MessageDef* m, const char* name, size_t len, + upb_value v, upb_Arena* a) { + return upb_strtable_insert(&m->ntof, name, len, v, a); } -/* Adds a symbol |v| to the symtab, which must be a def pointer previously - * packed with pack_def(). The def's pointer to upb_FileDef* must be set before - * adding, so we know which entries to remove if building this file fails. */ -static void symtab_add(symtab_addctx* ctx, const char* name, upb_value v) { - // TODO: table should support an operation "tryinsert" to avoid the double - // lookup. - if (upb_strtable_lookup(&ctx->symtab->syms, name, NULL)) { - symtab_errf(ctx, "duplicate symbol '%s'", name); - } - size_t len = strlen(name); - CHK_OOM(upb_strtable_insert(&ctx->symtab->syms, name, len, v, - ctx->symtab->arena)); -} - -static bool remove_component(char* base, size_t* len) { - if (*len == 0) return false; +bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, + const char* name, size_t len, + const upb_FieldDef** out_f, + const upb_OneofDef** out_o) { + upb_value val; - for (size_t i = *len - 1; i > 0; i--) { - if (base[i] == '.') { - *len = i; - return true; - } + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return false; } - *len = 0; - return true; + const upb_FieldDef* f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); + const upb_OneofDef* o = _upb_DefType_Unpack(val, UPB_DEFTYPE_ONEOF); + if (out_f) *out_f = f; + if (out_o) *out_o = o; + return f || o; /* False if this was a JSON name. */ } -/* Given a symbol and the base symbol inside which it is defined, find the - * symbol's definition in t. */ -static const void* symtab_resolveany(symtab_addctx* ctx, - const char* from_name_dbg, - const char* base, upb_StringView sym, - upb_deftype_t* type) { - const upb_strtable* t = &ctx->symtab->syms; - if (sym.size == 0) goto notfound; - upb_value v; - if (sym.data[0] == '.') { - /* Symbols starting with '.' are absolute, so we do a single lookup. - * Slice to omit the leading '.' */ - if (!upb_strtable_lookup2(t, sym.data + 1, sym.size - 1, &v)) { - goto notfound; - } - } else { - /* Remove components from base until we find an entry or run out. */ - size_t baselen = base ? strlen(base) : 0; - char* tmp = malloc(sym.size + baselen + 1); - while (1) { - char* p = tmp; - if (baselen) { - memcpy(p, base, baselen); - p[baselen] = '.'; - p += baselen + 1; - } - memcpy(p, sym.data, sym.size); - p += sym.size; - if (upb_strtable_lookup2(t, tmp, p - tmp, &v)) { - break; - } - if (!remove_component(tmp, &baselen)) { - free(tmp); - goto notfound; - } - } - free(tmp); +const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; + const upb_FieldDef* f; + + if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; } - *type = deftype(v); - return unpack_def(v, *type); + f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); + if (!f) f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD_JSONNAME); -notfound: - symtab_errf(ctx, "couldn't resolve name '" UPB_STRINGVIEW_FORMAT "'", - UPB_STRINGVIEW_ARGS(sym)); + return f; } -static const void* symtab_resolve(symtab_addctx* ctx, const char* from_name_dbg, - const char* base, upb_StringView sym, - upb_deftype_t type) { - upb_deftype_t found_type; - const void* ret = - symtab_resolveany(ctx, from_name_dbg, base, sym, &found_type); - if (ret && found_type != type) { - symtab_errf(ctx, - "type mismatch when resolving %s: couldn't find " - "name " UPB_STRINGVIEW_FORMAT " with type=%d", - from_name_dbg, UPB_STRINGVIEW_ARGS(sym), (int)type); - } - return ret; +int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) { + return m->ext_range_count; } -static void create_oneofdef( - symtab_addctx* ctx, upb_MessageDef* m, - const google_protobuf_OneofDescriptorProto* oneof_proto, - const upb_OneofDef* _o) { - upb_OneofDef* o = (upb_OneofDef*)_o; - upb_StringView name = google_protobuf_OneofDescriptorProto_name(oneof_proto); - upb_value v; - - o->parent = m; - o->full_name = makefullname(ctx, m->full_name, name); - o->field_count = 0; - o->synthetic = false; - - SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); +int upb_MessageDef_FieldCount(const upb_MessageDef* m) { + return m->field_count; +} - upb_value existing_v; - if (upb_strtable_lookup2(&m->ntof, name.data, name.size, &existing_v)) { - symtab_errf(ctx, "duplicate oneof name (%s)", o->full_name); - } +int upb_MessageDef_OneofCount(const upb_MessageDef* m) { + return m->oneof_count; +} - v = pack_def(o, UPB_DEFTYPE_ONEOF); - CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, v, ctx->arena)); +int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m) { + return m->nested_msg_count; +} - CHK_OOM(upb_inttable_init(&o->itof, ctx->arena)); - CHK_OOM(upb_strtable_init(&o->ntof, 4, ctx->arena)); +int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m) { + return m->nested_enum_count; } -static str_t* newstr(symtab_addctx* ctx, const char* data, size_t len) { - str_t* ret = symtab_alloc(ctx, sizeof(*ret) + len); - CHK_OOM(ret); - ret->len = len; - if (len) memcpy(ret->str, data, len); - ret->str[len] = '\0'; - return ret; +int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m) { + return m->nested_ext_count; } -static bool upb_DefPool_TryGetChar(const char** src, const char* end, - char* ch) { - if (*src == end) return false; - *ch = **src; - *src += 1; - return true; +const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m) { + return m->layout; } -static char upb_DefPool_TryGetHexDigit(symtab_addctx* ctx, - const upb_FieldDef* f, const char** src, - const char* end) { - char ch; - if (!upb_DefPool_TryGetChar(src, end, &ch)) return -1; - if ('0' <= ch && ch <= '9') { - return ch - '0'; - } - ch = upb_ascii_lower(ch); - if ('a' <= ch && ch <= 'f') { - return ch - 'a' + 0xa; - } - *src -= 1; // Char wasn't actually a hex digit. - return -1; +const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->ext_range_count); + return _upb_ExtensionRange_At(m->ext_ranges, i); } -static char upb_DefPool_ParseHexEscape(symtab_addctx* ctx, - const upb_FieldDef* f, const char** src, - const char* end) { - char hex_digit = upb_DefPool_TryGetHexDigit(ctx, f, src, end); - if (hex_digit < 0) { - symtab_errf(ctx, - "\\x cannot be followed by non-hex digit in field '%s' default", - upb_FieldDef_FullName(f)); - return 0; - } - unsigned int ret = hex_digit; - while ((hex_digit = upb_DefPool_TryGetHexDigit(ctx, f, src, end)) >= 0) { - ret = (ret << 4) | hex_digit; - } - if (ret > 0xff) { - symtab_errf(ctx, "Value of hex escape in field %s exceeds 8 bits", - upb_FieldDef_FullName(f)); - return 0; - } - return ret; +const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->field_count); + return _upb_FieldDef_At(m->fields, i); } -char upb_DefPool_TryGetOctalDigit(const char** src, const char* end) { - char ch; - if (!upb_DefPool_TryGetChar(src, end, &ch)) return -1; - if ('0' <= ch && ch <= '7') { - return ch - '0'; - } - *src -= 1; // Char wasn't actually an octal digit. - return -1; +const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->oneof_count); + return _upb_OneofDef_At(m->oneofs, i); } -static char upb_DefPool_ParseOctalEscape(symtab_addctx* ctx, - const upb_FieldDef* f, - const char** src, const char* end) { - char ch = 0; - for (int i = 0; i < 3; i++) { - char digit; - if ((digit = upb_DefPool_TryGetOctalDigit(src, end)) >= 0) { - ch = (ch << 3) | digit; - } - } - return ch; +const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->nested_msg_count); + return &m->nested_msgs[i]; } -static char upb_DefPool_ParseEscape(symtab_addctx* ctx, const upb_FieldDef* f, - const char** src, const char* end) { - char ch; - if (!upb_DefPool_TryGetChar(src, end, &ch)) { - symtab_errf(ctx, "unterminated escape sequence in field %s", - upb_FieldDef_FullName(f)); - return 0; - } - switch (ch) { - case 'a': - return '\a'; - case 'b': - return '\b'; - case 'f': - return '\f'; - case 'n': - return '\n'; - case 'r': - return '\r'; - case 't': - return '\t'; - case 'v': - return '\v'; - case '\\': - return '\\'; - case '\'': - return '\''; - case '\"': - return '\"'; - case '?': - return '\?'; - case 'x': - case 'X': - return upb_DefPool_ParseHexEscape(ctx, f, src, end); - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - *src -= 1; - return upb_DefPool_ParseOctalEscape(ctx, f, src, end); - } - symtab_errf(ctx, "Unknown escape sequence: \\%c", ch); +const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->nested_enum_count); + return _upb_EnumDef_At(m->nested_enums, i); +} + +const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->nested_ext_count); + return _upb_FieldDef_At(m->nested_exts, i); } -static str_t* unescape(symtab_addctx* ctx, const upb_FieldDef* f, - const char* data, size_t len) { - // Size here is an upper bound; escape sequences could ultimately shrink it. - str_t* ret = symtab_alloc(ctx, sizeof(*ret) + len); - char* dst = &ret->str[0]; - const char* src = data; - const char* end = data + len; +upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m) { + return m->well_known_type; +} - while (src < end) { - if (*src == '\\') { - src++; - *dst++ = upb_DefPool_ParseEscape(ctx, f, &src, end); - } else { - *dst++ = *src++; - } - } +bool _upb_MessageDef_InMessageSet(const upb_MessageDef* m) { + return m->in_message_set; +} - ret->len = dst - &ret->str[0]; - return ret; +const upb_FieldDef* upb_MessageDef_FindFieldByName(const upb_MessageDef* m, + const char* name) { + return upb_MessageDef_FindFieldByNameWithSize(m, name, strlen(name)); } -static void parse_default(symtab_addctx* ctx, const char* str, size_t len, - upb_FieldDef* f) { - char* end; - char nullz[64]; - errno = 0; +const upb_OneofDef* upb_MessageDef_FindOneofByName(const upb_MessageDef* m, + const char* name) { + return upb_MessageDef_FindOneofByNameWithSize(m, name, strlen(name)); +} - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Int32: - case kUpb_CType_Int64: - case kUpb_CType_UInt32: - case kUpb_CType_UInt64: - case kUpb_CType_Double: - case kUpb_CType_Float: - /* Standard C number parsing functions expect null-terminated strings. */ - if (len >= sizeof(nullz) - 1) { - symtab_errf(ctx, "Default too long: %.*s", (int)len, str); - } - memcpy(nullz, str, len); - nullz[len] = '\0'; - str = nullz; - break; - default: - break; +bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m) { + return google_protobuf_MessageOptions_map_entry(upb_MessageDef_Options(m)); +} + +bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m) { + return google_protobuf_MessageOptions_message_set_wire_format( + upb_MessageDef_Options(m)); +} + +static upb_MiniTable* _upb_MessageDef_MakeMiniTable(upb_DefBuilder* ctx, + const upb_MessageDef* m) { + if (google_protobuf_MessageOptions_message_set_wire_format(m->opts)) { + return upb_MiniTable_BuildMessageSet(kUpb_MiniTablePlatform_Native, + ctx->arena); } - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Int32: { - long val = strtol(str, &end, 0); - if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.sint = val; - break; - } - case kUpb_CType_Enum: { - const upb_EnumDef* e = f->sub.enumdef; - const upb_EnumValueDef* ev = - upb_EnumDef_FindValueByNameWithSize(e, str, len); - if (!ev) { - goto invalid; - } - f->defaultval.sint = ev->number; - break; - } - case kUpb_CType_Int64: { - long long val = strtoll(str, &end, 0); - if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.sint = val; - break; - } - case kUpb_CType_UInt32: { - unsigned long val = strtoul(str, &end, 0); - if (val > UINT32_MAX || errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.uint = val; - break; - } - case kUpb_CType_UInt64: { - unsigned long long val = strtoull(str, &end, 0); - if (val > UINT64_MAX || errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.uint = val; - break; - } - case kUpb_CType_Double: { - double val = strtod(str, &end); - if (errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.dbl = val; - break; - } - case kUpb_CType_Float: { - float val = strtof(str, &end); - if (errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.flt = val; - break; - } - case kUpb_CType_Bool: { - if (streql2(str, len, "false")) { - f->defaultval.boolean = false; - } else if (streql2(str, len, "true")) { - f->defaultval.boolean = true; - } else { - goto invalid; - } - break; + if (upb_MessageDef_IsMapEntry(m)) { + if (m->field_count != 2) { + _upb_DefBuilder_Errf(ctx, "invalid map (%s)", m->full_name); } - case kUpb_CType_String: - f->defaultval.str = newstr(ctx, str, len); - break; - case kUpb_CType_Bytes: - f->defaultval.str = unescape(ctx, f, str, len); - break; - case kUpb_CType_Message: - /* Should not have a default value. */ - symtab_errf(ctx, "Message should not have a default (%s)", - upb_FieldDef_FullName(f)); + + const upb_FieldDef* f0 = upb_MessageDef_Field(m, 0); + const upb_FieldDef* f1 = upb_MessageDef_Field(m, 1); + const upb_FieldType t0 = upb_FieldDef_Type(f0); + const upb_FieldType t1 = upb_FieldDef_Type(f1); + + const bool is_proto3_enum = + (t1 == kUpb_FieldType_Enum) && !_upb_FieldDef_IsClosedEnum(f1); + UPB_ASSERT(_upb_FieldDef_LayoutIndex(f0) == 0); + UPB_ASSERT(_upb_FieldDef_LayoutIndex(f1) == 1); + + return upb_MiniTable_BuildMapEntry( + t0, t1, is_proto3_enum, kUpb_MiniTablePlatform_Native, ctx->arena); } - return; + upb_StringView desc; + bool ok = upb_MessageDef_MiniDescriptorEncode(m, ctx->tmp_arena, &desc); + if (!ok) _upb_DefBuilder_OomErr(ctx); -invalid: - symtab_errf(ctx, "Invalid default '%.*s' for field %s of type %d", (int)len, - str, upb_FieldDef_FullName(f), (int)upb_FieldDef_Type(f)); + void** scratch_data = _upb_DefPool_ScratchData(ctx->symtab); + size_t* scratch_size = _upb_DefPool_ScratchSize(ctx->symtab); + upb_MiniTable* ret = upb_MiniTable_BuildWithBuf( + desc.data, desc.size, kUpb_MiniTablePlatform_Native, ctx->arena, + scratch_data, scratch_size, ctx->status); + if (!ret) _upb_DefBuilder_FailJmp(ctx); + return ret; } -static void set_default_default(symtab_addctx* ctx, upb_FieldDef* f) { - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Int32: - case kUpb_CType_Int64: - f->defaultval.sint = 0; - break; - case kUpb_CType_UInt64: - case kUpb_CType_UInt32: - f->defaultval.uint = 0; - break; - case kUpb_CType_Double: - case kUpb_CType_Float: - f->defaultval.dbl = 0; - break; - case kUpb_CType_String: - case kUpb_CType_Bytes: - f->defaultval.str = newstr(ctx, NULL, 0); - break; - case kUpb_CType_Bool: - f->defaultval.boolean = false; - break; - case kUpb_CType_Enum: - f->defaultval.sint = f->sub.enumdef->values[0].number; - case kUpb_CType_Message: - break; +void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m) { + for (int i = 0; i < m->field_count; i++) { + upb_FieldDef* f = (upb_FieldDef*)upb_MessageDef_Field(m, i); + _upb_FieldDef_Resolve(ctx, upb_MessageDef_FullName(m), f); } -} -static void create_fielddef( - symtab_addctx* ctx, const char* prefix, upb_MessageDef* m, - const google_protobuf_FieldDescriptorProto* field_proto, - const upb_FieldDef* _f, bool is_extension) { - upb_FieldDef* f = (upb_FieldDef*)_f; - upb_StringView name; - const char* full_name; - const char* json_name; - const char* shortname; - int32_t field_number; + if (!ctx->layout) { + m->layout = _upb_MessageDef_MakeMiniTable(ctx, m); + if (!m->layout) _upb_DefBuilder_OomErr(ctx); + } - f->file = ctx->file; /* Must happen prior to symtab_add(). */ + m->in_message_set = false; + for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) { + upb_FieldDef* ext = (upb_FieldDef*)upb_MessageDef_NestedExtension(m, i); + _upb_FieldDef_Resolve(ctx, upb_MessageDef_FullName(m), ext); + if (upb_FieldDef_Type(ext) == kUpb_FieldType_Message && + upb_FieldDef_Label(ext) == kUpb_Label_Optional && + upb_FieldDef_MessageSubDef(ext) == m && + google_protobuf_MessageOptions_message_set_wire_format( + upb_MessageDef_Options(upb_FieldDef_ContainingType(ext)))) { + m->in_message_set = true; + } + } - if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { - symtab_errf(ctx, "field has no name"); + for (int i = 0; i < upb_MessageDef_NestedMessageCount(m); i++) { + upb_MessageDef* n = (upb_MessageDef*)upb_MessageDef_NestedMessage(m, i); + _upb_MessageDef_Resolve(ctx, n); } +} - name = google_protobuf_FieldDescriptorProto_name(field_proto); - check_ident(ctx, name, false); - full_name = makefullname(ctx, prefix, name); - shortname = shortdefname(full_name); +void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m, + const upb_FieldDef* f) { + const int32_t field_number = upb_FieldDef_Number(f); - if (google_protobuf_FieldDescriptorProto_has_json_name(field_proto)) { - json_name = strviewdup( - ctx, google_protobuf_FieldDescriptorProto_json_name(field_proto)); - f->has_json_name_ = true; - } else { - json_name = makejsonname(ctx, shortname); - f->has_json_name_ = false; + if (field_number <= 0 || field_number > kUpb_MaxFieldNumber) { + _upb_DefBuilder_Errf(ctx, "invalid field number (%u)", field_number); } - field_number = google_protobuf_FieldDescriptorProto_number(field_proto); + const char* json_name = upb_FieldDef_JsonName(f); + const char* shortname = upb_FieldDef_Name(f); + const size_t shortnamelen = strlen(shortname); - f->full_name = full_name; - f->json_name = json_name; - f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto); - f->number_ = field_number; - f->scope.oneof = NULL; - f->proto3_optional_ = - google_protobuf_FieldDescriptorProto_proto3_optional(field_proto); + upb_value v = upb_value_constptr(f); - bool has_type = google_protobuf_FieldDescriptorProto_has_type(field_proto); - bool has_type_name = - google_protobuf_FieldDescriptorProto_has_type_name(field_proto); + upb_value existing_v; + if (upb_strtable_lookup(&m->ntof, shortname, &existing_v)) { + _upb_DefBuilder_Errf(ctx, "duplicate field name (%s)", shortname); + } - f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto); + const upb_value field_v = _upb_DefType_Pack(f, UPB_DEFTYPE_FIELD); + bool ok = + _upb_MessageDef_Insert(m, shortname, shortnamelen, field_v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); - if (has_type) { - switch (f->type_) { - case kUpb_FieldType_Message: - case kUpb_FieldType_Group: - case kUpb_FieldType_Enum: - if (!has_type_name) { - symtab_errf(ctx, "field of type %d requires type name (%s)", - (int)f->type_, full_name); - } - break; - default: - if (has_type_name) { - symtab_errf(ctx, "invalid type for field with type_name set (%s, %d)", - full_name, (int)f->type_); - } + if (strcmp(shortname, json_name) != 0) { + if (upb_strtable_lookup(&m->ntof, json_name, &v)) { + _upb_DefBuilder_Errf(ctx, "duplicate json_name (%s)", json_name); } - } else if (has_type_name) { - f->type_ = - FIELD_TYPE_UNSPECIFIED; // We'll fill this in in resolve_fielddef(). + + const size_t json_size = strlen(json_name); + const upb_value json_v = _upb_DefType_Pack(f, UPB_DEFTYPE_FIELD_JSONNAME); + ok = _upb_MessageDef_Insert(m, json_name, json_size, json_v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + } + + if (upb_inttable_lookup(&m->itof, field_number, NULL)) { + _upb_DefBuilder_Errf(ctx, "duplicate field number (%u)", field_number); } - if (!is_extension) { - /* direct message field. */ - upb_value v, field_v, json_v, existing_v; - size_t json_size; + ok = upb_inttable_insert(&m->itof, field_number, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} - if (field_number <= 0 || field_number > kUpb_MaxFieldNumber) { - symtab_errf(ctx, "invalid field number (%u)", field_number); +void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx, + const upb_MessageDef* m) { + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + const upb_MessageDef* sub_m = upb_FieldDef_MessageSubDef(f); + const upb_EnumDef* sub_e = upb_FieldDef_EnumSubDef(f); + const int layout_index = _upb_FieldDef_LayoutIndex(f); + upb_MiniTable* mt = (upb_MiniTable*)upb_MessageDef_MiniTable(m); + + UPB_ASSERT(layout_index < m->field_count); + upb_MiniTable_Field* mt_f = + (upb_MiniTable_Field*)&m->layout->fields[layout_index]; + if (sub_m) { + if (!mt->subs) { + _upb_DefBuilder_Errf(ctx, "invalid submsg for (%s)", m->full_name); + } + UPB_ASSERT(mt_f); + UPB_ASSERT(sub_m->layout); + upb_MiniTable_SetSubMessage(mt, mt_f, sub_m->layout); + } else if (_upb_FieldDef_IsClosedEnum(f)) { + upb_MiniTable_SetSubEnum(mt, mt_f, _upb_EnumDef_MiniTable(sub_e)); } + } - f->index_ = f - m->fields; - f->msgdef = m; - f->is_extension_ = false; + for (int i = 0; i < m->nested_msg_count; i++) { + _upb_MessageDef_LinkMiniTable(ctx, upb_MessageDef_NestedMessage(m, i)); + } +} - field_v = pack_def(f, UPB_DEFTYPE_FIELD); - json_v = pack_def(f, UPB_DEFTYPE_FIELD_JSONNAME); - v = upb_value_constptr(f); - json_size = strlen(json_name); +static uint64_t _upb_MessageDef_Modifiers(const upb_MessageDef* m) { + uint64_t out = 0; + if (upb_FileDef_Syntax(m->file) == kUpb_Syntax_Proto3) { + out |= kUpb_MessageModifier_ValidateUtf8; + out |= kUpb_MessageModifier_DefaultIsPacked; + } + if (m->ext_range_count) { + out |= kUpb_MessageModifier_IsExtendable; + } + return out; +} - if (upb_strtable_lookup(&m->ntof, shortname, &existing_v)) { - symtab_errf(ctx, "duplicate field name (%s)", shortname); - } +bool upb_MessageDef_MiniDescriptorEncode(const upb_MessageDef* m, upb_Arena* a, + upb_StringView* out) { + upb_DescState s; + _upb_DescState_Init(&s); - CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, field_v, - ctx->arena)); + const upb_FieldDef** sorted = NULL; + if (!m->is_sorted) { + sorted = _upb_FieldDefs_Sorted(m->fields, m->field_count, a); + if (!sorted) return false; + } - if (strcmp(shortname, json_name) != 0) { - if (upb_strtable_lookup(&m->ntof, json_name, &v)) { - symtab_errf(ctx, "duplicate json_name (%s)", json_name); - } else { - CHK_OOM(upb_strtable_insert(&m->ntof, json_name, json_size, json_v, - ctx->arena)); - } - } + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = + upb_MtDataEncoder_StartMessage(&s.e, s.ptr, _upb_MessageDef_Modifiers(m)); - if (upb_inttable_lookup(&m->itof, field_number, NULL)) { - symtab_errf(ctx, "duplicate field number (%u)", field_number); - } + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = sorted ? sorted[i] : upb_MessageDef_Field(m, i); + const upb_FieldType type = upb_FieldDef_Type(f); + const int number = upb_FieldDef_Number(f); + const uint64_t modifiers = _upb_FieldDef_Modifiers(f); - CHK_OOM(upb_inttable_insert(&m->itof, field_number, v, ctx->arena)); + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_PutField(&s.e, s.ptr, type, number, modifiers); + } - if (ctx->layout) { - const upb_MiniTable_Field* fields = m->layout->fields; - int count = m->layout->field_count; - bool found = false; - for (int i = 0; i < count; i++) { - if (fields[i].number == field_number) { - f->layout_index = i; - found = true; - break; - } - } - UPB_ASSERT(found); - } - } else { - /* extension field. */ - f->is_extension_ = true; - f->scope.extension_scope = m; - symtab_add(ctx, full_name, pack_def(f, UPB_DEFTYPE_EXT)); - f->layout_index = ctx->ext_count++; - if (ctx->layout) { - UPB_ASSERT(ctx->file->ext_layouts[f->layout_index]->field.number == - field_number); + for (int i = 0; i < m->oneof_count; i++) { + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_StartOneof(&s.e, s.ptr); + + const upb_OneofDef* o = upb_MessageDef_Oneof(m, i); + const int field_count = upb_OneofDef_FieldCount(o); + for (int j = 0; j < field_count; j++) { + const int number = upb_FieldDef_Number(upb_OneofDef_Field(o, j)); + + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_PutOneofField(&s.e, s.ptr, number); } } - if (f->type_ < kUpb_FieldType_Double || f->type_ > kUpb_FieldType_SInt64) { - symtab_errf(ctx, "invalid type for field %s (%d)", f->full_name, f->type_); - } + if (!_upb_DescState_Grow(&s, a)) return false; + *s.ptr = '\0'; - if (f->label_ < kUpb_Label_Optional || f->label_ > kUpb_Label_Repeated) { - symtab_errf(ctx, "invalid label for field %s (%d)", f->full_name, - f->label_); - } + out->data = s.buf; + out->size = s.ptr - s.buf; + return true; +} - /* We can't resolve the subdef or (in the case of extensions) the containing - * message yet, because it may not have been defined yet. We stash a pointer - * to the field_proto until later when we can properly resolve it. */ - f->sub.unresolved = field_proto; +static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_DescriptorProto* msg_proto, + const upb_MessageDef* containing_type, + upb_MessageDef* m) { + const google_protobuf_OneofDescriptorProto* const* oneofs; + const google_protobuf_FieldDescriptorProto* const* fields; + const google_protobuf_DescriptorProto_ExtensionRange* const* ext_ranges; + size_t n_oneof, n_field, n_ext_range, n_enum, n_ext, n_msg; + upb_StringView name; - if (f->label_ == kUpb_Label_Required && - f->file->syntax == kUpb_Syntax_Proto3) { - symtab_errf(ctx, "proto3 fields cannot be required (%s)", f->full_name); + // Must happen before _upb_DefBuilder_Add() + m->file = _upb_DefBuilder_File(ctx); + + m->containing_type = containing_type; + m->is_sorted = true; + + name = google_protobuf_DescriptorProto_name(msg_proto); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); + + m->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + _upb_DefBuilder_Add(ctx, m->full_name, _upb_DefType_Pack(m, UPB_DEFTYPE_MSG)); + + oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n_oneof); + fields = google_protobuf_DescriptorProto_field(msg_proto, &n_field); + ext_ranges = google_protobuf_DescriptorProto_extension_range(msg_proto, &n_ext_range); + + bool ok = upb_inttable_init(&m->itof, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + if (ctx->layout) { + /* create_fielddef() below depends on this being set. */ + UPB_ASSERT(ctx->msg_count < ctx->layout->msg_count); + m->layout = ctx->layout->msgs[ctx->msg_count++]; + UPB_ASSERT(n_field == m->layout->field_count); + } else { + /* Allocate now (to allow cross-linking), populate later. */ + m->layout = _upb_DefBuilder_Alloc( + ctx, sizeof(*m->layout) + sizeof(_upb_FastTable_Entry)); } - if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { - int oneof_index = - google_protobuf_FieldDescriptorProto_oneof_index(field_proto); - upb_OneofDef* oneof; - upb_value v = upb_value_constptr(f); + UBP_DEF_SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); - if (upb_FieldDef_Label(f) != kUpb_Label_Optional) { - symtab_errf(ctx, "fields in oneof must have OPTIONAL label (%s)", - f->full_name); - } + m->oneof_count = n_oneof; + m->oneofs = _upb_OneofDefs_New(ctx, n_oneof, oneofs, m); - if (!m) { - symtab_errf(ctx, "oneof_index provided for extension field (%s)", - f->full_name); - } + m->field_count = n_field; + m->fields = + _upb_FieldDefs_New(ctx, n_field, fields, m->full_name, m, &m->is_sorted); - if (oneof_index >= m->oneof_count) { - symtab_errf(ctx, "oneof_index out of range (%s)", f->full_name); - } + m->ext_range_count = n_ext_range; + m->ext_ranges = _upb_ExtensionRanges_New(ctx, n_ext_range, ext_ranges, m); - oneof = (upb_OneofDef*)&m->oneofs[oneof_index]; - f->scope.oneof = oneof; + const size_t synthetic_count = _upb_OneofDefs_Finalize(ctx, m); + m->real_oneof_count = m->oneof_count - synthetic_count; - oneof->field_count++; - if (f->proto3_optional_) { - oneof->synthetic = true; - } - CHK_OOM(upb_inttable_insert(&oneof->itof, f->number_, v, ctx->arena)); - CHK_OOM( - upb_strtable_insert(&oneof->ntof, name.data, name.size, v, ctx->arena)); - } else { - if (f->proto3_optional_) { - symtab_errf(ctx, "field with proto3_optional was not in a oneof (%s)", - f->full_name); - } - } + assign_msg_wellknowntype(m); + upb_inttable_compact(&m->itof, ctx->arena); - SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); + const google_protobuf_EnumDescriptorProto* const* enums = + google_protobuf_DescriptorProto_enum_type(msg_proto, &n_enum); + m->nested_enum_count = n_enum; + m->nested_enums = _upb_EnumDefs_New(ctx, n_enum, enums, m); - if (google_protobuf_FieldOptions_has_packed(f->opts)) { - f->packed_ = google_protobuf_FieldOptions_packed(f->opts); - } else { - /* Repeated fields default to packed for proto3 only. */ - f->packed_ = upb_FieldDef_IsPrimitive(f) && - f->label_ == kUpb_Label_Repeated && - f->file->syntax == kUpb_Syntax_Proto3; - } -} + const google_protobuf_FieldDescriptorProto* const* exts = + google_protobuf_DescriptorProto_extension(msg_proto, &n_ext); + m->nested_ext_count = n_ext; + m->nested_exts = _upb_FieldDefs_New(ctx, n_ext, exts, m->full_name, m, NULL); -static void create_service( - symtab_addctx* ctx, const google_protobuf_ServiceDescriptorProto* svc_proto, - const upb_ServiceDef* _s) { - upb_ServiceDef* s = (upb_ServiceDef*)_s; - upb_StringView name; - const google_protobuf_MethodDescriptorProto* const* methods; - size_t i, n; + const google_protobuf_DescriptorProto* const* msgs = + google_protobuf_DescriptorProto_nested_type(msg_proto, &n_msg); + m->nested_msg_count = n_msg; + m->nested_msgs = _upb_MessageDefs_New(ctx, n_msg, msgs, m); +} - s->file = ctx->file; /* Must happen prior to symtab_add. */ +// Allocate and initialize an array of |n| message defs. +upb_MessageDef* _upb_MessageDefs_New( + upb_DefBuilder* ctx, int n, const google_protobuf_DescriptorProto* const* protos, + const upb_MessageDef* containing_type) { + _upb_DefType_CheckPadding(sizeof(upb_MessageDef)); - name = google_protobuf_ServiceDescriptorProto_name(svc_proto); - check_ident(ctx, name, false); - s->full_name = makefullname(ctx, ctx->file->package, name); - symtab_add(ctx, s->full_name, pack_def(s, UPB_DEFTYPE_SERVICE)); + const char* name = containing_type ? containing_type->full_name + : _upb_FileDef_RawPackage(ctx->file); - methods = google_protobuf_ServiceDescriptorProto_method(svc_proto, &n); + upb_MessageDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MessageDef) * n); + for (int i = 0; i < n; i++) { + create_msgdef(ctx, name, protos[i], containing_type, &m[i]); + } + return m; +} - s->method_count = n; - s->methods = symtab_alloc(ctx, sizeof(*s->methods) * n); - SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, svc_proto); - for (i = 0; i < n; i++) { - const google_protobuf_MethodDescriptorProto* method_proto = methods[i]; - upb_MethodDef* m = (upb_MethodDef*)&s->methods[i]; - upb_StringView name = - google_protobuf_MethodDescriptorProto_name(method_proto); - - m->service = s; - m->full_name = makefullname(ctx, s->full_name, name); - m->index = i; - m->client_streaming = - google_protobuf_MethodDescriptorProto_client_streaming(method_proto); - m->server_streaming = - google_protobuf_MethodDescriptorProto_server_streaming(method_proto); - m->input_type = symtab_resolve( - ctx, m->full_name, m->full_name, - google_protobuf_MethodDescriptorProto_input_type(method_proto), - UPB_DEFTYPE_MSG); - m->output_type = symtab_resolve( - ctx, m->full_name, m->full_name, - google_protobuf_MethodDescriptorProto_output_type(method_proto), - UPB_DEFTYPE_MSG); - - SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, method_proto); - } -} - -static int count_bits_debug(uint64_t x) { - // For assertions only, speed does not matter. - int n = 0; - while (x) { - if (x & 1) n++; - x >>= 1; - } - return n; -} - -static int compare_int32(const void* a_ptr, const void* b_ptr) { - int32_t a = *(int32_t*)a_ptr; - int32_t b = *(int32_t*)b_ptr; - return a < b ? -1 : (a == b ? 0 : 1); -} - -upb_MiniTable_Enum* create_enumlayout(symtab_addctx* ctx, - const upb_EnumDef* e) { - int n = 0; - uint64_t mask = 0; - - for (int i = 0; i < e->value_count; i++) { - uint32_t val = (uint32_t)e->values[i].number; - if (val < 64) { - mask |= 1ULL << val; - } else { - n++; - } - } +// Must be last. - int32_t* values = symtab_alloc(ctx, sizeof(*values) * n); +struct upb_MethodDef { + const google_protobuf_MethodOptions* opts; + upb_ServiceDef* service; + const char* full_name; + const upb_MessageDef* input_type; + const upb_MessageDef* output_type; + int index; + bool client_streaming; + bool server_streaming; +}; - if (n) { - int32_t* p = values; - - // Add values outside the bitmask range to the list, as described in the - // comments for upb_MiniTable_Enum. - for (int i = 0; i < e->value_count; i++) { - int32_t val = e->values[i].number; - if ((uint32_t)val >= 64) { - *p++ = val; - } - } - UPB_ASSERT(p == values + n); - } +upb_MethodDef* _upb_MethodDef_At(const upb_MethodDef* m, int i) { + return (upb_MethodDef*)&m[i]; +} - // Enums can have duplicate values; we must sort+uniq them. - if (values) qsort(values, n, sizeof(*values), &compare_int32); +const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m) { + return m->service; +} - int dst = 0; - for (int i = 0; i < n; dst++) { - int32_t val = values[i]; - while (i < n && values[i] == val) i++; // Skip duplicates. - values[dst] = val; - } - n = dst; +const google_protobuf_MethodOptions* upb_MethodDef_Options(const upb_MethodDef* m) { + return m->opts; +} - UPB_ASSERT(upb_inttable_count(&e->iton) == n + count_bits_debug(mask)); +bool upb_MethodDef_HasOptions(const upb_MethodDef* m) { + return m->opts != (void*)kUpbDefOptDefault; +} - upb_MiniTable_Enum* layout = symtab_alloc(ctx, sizeof(*layout)); - layout->value_count = n; - layout->mask = mask; - layout->values = values; +const char* upb_MethodDef_FullName(const upb_MethodDef* m) { + return m->full_name; +} - return layout; +const char* upb_MethodDef_Name(const upb_MethodDef* m) { + return _upb_DefBuilder_FullToShort(m->full_name); } -static void create_enumvaldef( - symtab_addctx* ctx, const char* prefix, - const google_protobuf_EnumValueDescriptorProto* val_proto, upb_EnumDef* e, - int i) { - upb_EnumValueDef* val = (upb_EnumValueDef*)&e->values[i]; - upb_StringView name = - google_protobuf_EnumValueDescriptorProto_name(val_proto); - upb_value v = upb_value_constptr(val); +int upb_MethodDef_Index(const upb_MethodDef* m) { return m->index; } - val->parent = e; /* Must happen prior to symtab_add(). */ - val->full_name = makefullname(ctx, prefix, name); - val->number = google_protobuf_EnumValueDescriptorProto_number(val_proto); - symtab_add(ctx, val->full_name, pack_def(val, UPB_DEFTYPE_ENUMVAL)); +const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m) { + return m->input_type; +} - SET_OPTIONS(val->opts, EnumValueDescriptorProto, EnumValueOptions, val_proto); +const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m) { + return m->output_type; +} - if (i == 0 && e->file->syntax == kUpb_Syntax_Proto3 && val->number != 0) { - symtab_errf(ctx, "for proto3, the first enum value must be zero (%s)", - e->full_name); - } +bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m) { + return m->client_streaming; +} - CHK_OOM(upb_strtable_insert(&e->ntoi, name.data, name.size, v, ctx->arena)); +bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { + return m->server_streaming; +} - // Multiple enumerators can have the same number, first one wins. - if (!upb_inttable_lookup(&e->iton, val->number, NULL)) { - CHK_OOM(upb_inttable_insert(&e->iton, val->number, v, ctx->arena)); +static void create_method(upb_DefBuilder* ctx, + const google_protobuf_MethodDescriptorProto* method_proto, + upb_ServiceDef* s, upb_MethodDef* m) { + upb_StringView name = google_protobuf_MethodDescriptorProto_name(method_proto); + + m->service = s; + m->full_name = + _upb_DefBuilder_MakeFullName(ctx, upb_ServiceDef_FullName(s), name); + m->client_streaming = + google_protobuf_MethodDescriptorProto_client_streaming(method_proto); + m->server_streaming = + google_protobuf_MethodDescriptorProto_server_streaming(method_proto); + m->input_type = _upb_DefBuilder_Resolve( + ctx, m->full_name, m->full_name, + google_protobuf_MethodDescriptorProto_input_type(method_proto), UPB_DEFTYPE_MSG); + m->output_type = _upb_DefBuilder_Resolve( + ctx, m->full_name, m->full_name, + google_protobuf_MethodDescriptorProto_output_type(method_proto), UPB_DEFTYPE_MSG); + + UBP_DEF_SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, + method_proto); +} + +// Allocate and initialize an array of |n| method defs belonging to |s|. +upb_MethodDef* _upb_MethodDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_MethodDescriptorProto* const* protos, upb_ServiceDef* s) { + upb_MethodDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MethodDef) * n); + for (int i = 0; i < n; i++) { + create_method(ctx, protos[i], s, &m[i]); + m[i].index = i; } + return m; } -static void create_enumdef( - symtab_addctx* ctx, const char* prefix, - const google_protobuf_EnumDescriptorProto* enum_proto, - const upb_MessageDef* containing_type, const upb_EnumDef* _e) { - upb_EnumDef* e = (upb_EnumDef*)_e; - ; - const google_protobuf_EnumValueDescriptorProto* const* values; - upb_StringView name; - size_t i, n; - e->file = ctx->file; /* Must happen prior to symtab_add() */ - e->containing_type = containing_type; +#include +#include +#include - name = google_protobuf_EnumDescriptorProto_name(enum_proto); - check_ident(ctx, name, false); - e->full_name = makefullname(ctx, prefix, name); - symtab_add(ctx, e->full_name, pack_def(e, UPB_DEFTYPE_ENUM)); +// Must be last. - values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n); - CHK_OOM(upb_strtable_init(&e->ntoi, n, ctx->arena)); - CHK_OOM(upb_inttable_init(&e->iton, ctx->arena)); +struct upb_OneofDef { + const google_protobuf_OneofOptions* opts; + const upb_MessageDef* parent; + const char* full_name; + int field_count; + bool synthetic; + const upb_FieldDef** fields; + upb_strtable ntof; // lookup a field by name + upb_inttable itof; // lookup a field by number (index) +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif +}; - e->defaultval = 0; - e->value_count = n; - e->values = symtab_alloc(ctx, sizeof(*e->values) * n); +upb_OneofDef* _upb_OneofDef_At(const upb_OneofDef* o, int i) { + return (upb_OneofDef*)&o[i]; +} - if (n == 0) { - symtab_errf(ctx, "enums must contain at least one value (%s)", - e->full_name); - } +const google_protobuf_OneofOptions* upb_OneofDef_Options(const upb_OneofDef* o) { + return o->opts; +} - SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); +bool upb_OneofDef_HasOptions(const upb_OneofDef* o) { + return o->opts != (void*)kUpbDefOptDefault; +} - for (i = 0; i < n; i++) { - create_enumvaldef(ctx, prefix, values[i], e, i); - } +const char* upb_OneofDef_FullName(const upb_OneofDef* o) { + return o->full_name; +} - upb_inttable_compact(&e->iton, ctx->arena); +const char* upb_OneofDef_Name(const upb_OneofDef* o) { + return _upb_DefBuilder_FullToShort(o->full_name); +} - if (e->file->syntax == kUpb_Syntax_Proto2) { - if (ctx->layout) { - UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count); - e->layout = ctx->layout->enums[ctx->enum_count++]; - UPB_ASSERT(upb_inttable_count(&e->iton) == - e->layout->value_count + count_bits_debug(e->layout->mask)); - } else { - e->layout = create_enumlayout(ctx, e); - } - } else { - e->layout = NULL; - } +const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o) { + return o->parent; } -static void msgdef_create_nested( - symtab_addctx* ctx, const google_protobuf_DescriptorProto* msg_proto, - upb_MessageDef* m); +int upb_OneofDef_FieldCount(const upb_OneofDef* o) { return o->field_count; } -static void create_msgdef(symtab_addctx* ctx, const char* prefix, - const google_protobuf_DescriptorProto* msg_proto, - const upb_MessageDef* containing_type, - const upb_MessageDef* _m) { - upb_MessageDef* m = (upb_MessageDef*)_m; - const google_protobuf_OneofDescriptorProto* const* oneofs; - const google_protobuf_FieldDescriptorProto* const* fields; - const google_protobuf_DescriptorProto_ExtensionRange* const* ext_ranges; - size_t i, n_oneof, n_field, n_ext_range; - upb_StringView name; +const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i) { + UPB_ASSERT(i < o->field_count); + return o->fields[i]; +} - m->file = ctx->file; /* Must happen prior to symtab_add(). */ - m->containing_type = containing_type; +int upb_OneofDef_numfields(const upb_OneofDef* o) { return o->field_count; } - name = google_protobuf_DescriptorProto_name(msg_proto); - check_ident(ctx, name, false); +uint32_t upb_OneofDef_Index(const upb_OneofDef* o) { + // Compute index in our parent's array. + return o - upb_MessageDef_Oneof(o->parent, 0); +} - m->full_name = makefullname(ctx, prefix, name); - symtab_add(ctx, m->full_name, pack_def(m, UPB_DEFTYPE_MSG)); +bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o) { return o->synthetic; } - oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n_oneof); - fields = google_protobuf_DescriptorProto_field(msg_proto, &n_field); - ext_ranges = - google_protobuf_DescriptorProto_extension_range(msg_proto, &n_ext_range); +const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, + const char* name, + size_t size) { + upb_value val; + return upb_strtable_lookup2(&o->ntof, name, size, &val) + ? upb_value_getptr(val) + : NULL; +} - CHK_OOM(upb_inttable_init(&m->itof, ctx->arena)); - CHK_OOM(upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena)); +const upb_FieldDef* upb_OneofDef_LookupName(const upb_OneofDef* o, + const char* name) { + return upb_OneofDef_LookupNameWithSize(o, name, strlen(name)); +} - if (ctx->layout) { - /* create_fielddef() below depends on this being set. */ - UPB_ASSERT(ctx->msg_count < ctx->layout->msg_count); - m->layout = ctx->layout->msgs[ctx->msg_count++]; - UPB_ASSERT(n_field == m->layout->field_count); - } else { - /* Allocate now (to allow cross-linking), populate later. */ - m->layout = - symtab_alloc(ctx, sizeof(*m->layout) + sizeof(_upb_FastTable_Entry)); - } +const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, + uint32_t num) { + upb_value val; + return upb_inttable_lookup(&o->itof, num, &val) ? upb_value_getptr(val) + : NULL; +} - SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); +bool _upb_OneofDef_Insert(upb_OneofDef* o, const upb_FieldDef* f, + const char* name, size_t size, upb_Arena* a) { + o->field_count++; + if (_upb_FieldDef_IsProto3Optional(f)) o->synthetic = true; - m->oneof_count = n_oneof; - m->oneofs = symtab_alloc(ctx, sizeof(*m->oneofs) * n_oneof); - for (i = 0; i < n_oneof; i++) { - create_oneofdef(ctx, m, oneofs[i], &m->oneofs[i]); - } + const int number = upb_FieldDef_Number(f); + const upb_value v = upb_value_constptr(f); + return upb_inttable_insert(&o->itof, number, v, a) && + upb_strtable_insert(&o->ntof, name, size, v, a); +} - m->field_count = n_field; - m->fields = symtab_alloc(ctx, sizeof(*m->fields) * n_field); - for (i = 0; i < n_field; i++) { - create_fielddef(ctx, m->full_name, m, fields[i], &m->fields[i], - /* is_extension= */ false); - } +// Returns the synthetic count. +size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m) { + int synthetic_count = 0; - m->ext_range_count = n_ext_range; - m->ext_ranges = symtab_alloc(ctx, sizeof(*m->ext_ranges) * n_ext_range); - for (i = 0; i < n_ext_range; i++) { - const google_protobuf_DescriptorProto_ExtensionRange* r = ext_ranges[i]; - upb_ExtensionRange* r_def = (upb_ExtensionRange*)&m->ext_ranges[i]; - int32_t start = google_protobuf_DescriptorProto_ExtensionRange_start(r); - int32_t end = google_protobuf_DescriptorProto_ExtensionRange_end(r); - int32_t max = - google_protobuf_MessageOptions_message_set_wire_format(m->opts) - ? INT32_MAX - : kUpb_MaxFieldNumber + 1; + for (int i = 0; i < upb_MessageDef_OneofCount(m); i++) { + upb_OneofDef* o = (upb_OneofDef*)upb_MessageDef_Oneof(m, i); - // A full validation would also check that each range is disjoint, and that - // none of the fields overlap with the extension ranges, but we are just - // sanity checking here. - if (start < 1 || end <= start || end > max) { - symtab_errf(ctx, "Extension range (%d, %d) is invalid, message=%s\n", - (int)start, (int)end, m->full_name); + if (o->synthetic && o->field_count != 1) { + _upb_DefBuilder_Errf(ctx, + "Synthetic oneofs must have one field, not %d: %s", + o->field_count, upb_OneofDef_Name(o)); } - r_def->start = start; - r_def->end = end; - SET_OPTIONS(r_def->opts, DescriptorProto_ExtensionRange, - ExtensionRangeOptions, r); + if (o->synthetic) { + synthetic_count++; + } else if (synthetic_count != 0) { + _upb_DefBuilder_Errf( + ctx, "Synthetic oneofs must be after all other oneofs: %s", + upb_OneofDef_Name(o)); + } + + o->fields = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef*) * o->field_count); + o->field_count = 0; } - finalize_oneofs(ctx, m); - assign_msg_wellknowntype(m); - upb_inttable_compact(&m->itof, ctx->arena); - msgdef_create_nested(ctx, msg_proto, m); + for (int i = 0; i < upb_MessageDef_FieldCount(m); i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + upb_OneofDef* o = (upb_OneofDef*)upb_FieldDef_ContainingOneof(f); + if (o) { + o->fields[o->field_count++] = f; + } + } + + return synthetic_count; } -static void msgdef_create_nested( - symtab_addctx* ctx, const google_protobuf_DescriptorProto* msg_proto, - upb_MessageDef* m) { - size_t n; +static void create_oneofdef(upb_DefBuilder* ctx, upb_MessageDef* m, + const google_protobuf_OneofDescriptorProto* oneof_proto, + const upb_OneofDef* _o) { + upb_OneofDef* o = (upb_OneofDef*)_o; + upb_StringView name = google_protobuf_OneofDescriptorProto_name(oneof_proto); - const google_protobuf_EnumDescriptorProto* const* enums = - google_protobuf_DescriptorProto_enum_type(msg_proto, &n); - m->nested_enum_count = n; - m->nested_enums = symtab_alloc(ctx, sizeof(*m->nested_enums) * n); - for (size_t i = 0; i < n; i++) { - m->nested_enum_count = i + 1; - create_enumdef(ctx, m->full_name, enums[i], m, &m->nested_enums[i]); - } + o->parent = m; + o->full_name = + _upb_DefBuilder_MakeFullName(ctx, upb_MessageDef_FullName(m), name); + o->field_count = 0; + o->synthetic = false; - const google_protobuf_FieldDescriptorProto* const* exts = - google_protobuf_DescriptorProto_extension(msg_proto, &n); - m->nested_ext_count = n; - m->nested_exts = symtab_alloc(ctx, sizeof(*m->nested_exts) * n); - for (size_t i = 0; i < n; i++) { - create_fielddef(ctx, m->full_name, m, exts[i], &m->nested_exts[i], - /* is_extension= */ true); - ((upb_FieldDef*)&m->nested_exts[i])->index_ = i; - } + UBP_DEF_SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); - const google_protobuf_DescriptorProto* const* msgs = - google_protobuf_DescriptorProto_nested_type(msg_proto, &n); - m->nested_msg_count = n; - m->nested_msgs = symtab_alloc(ctx, sizeof(*m->nested_msgs) * n); - for (size_t i = 0; i < n; i++) { - create_msgdef(ctx, m->full_name, msgs[i], m, &m->nested_msgs[i]); + if (upb_MessageDef_FindByNameWithSize(m, name.data, name.size, NULL, NULL)) { + _upb_DefBuilder_Errf(ctx, "duplicate oneof name (%s)", o->full_name); } -} -static void resolve_subdef(symtab_addctx* ctx, const char* prefix, - upb_FieldDef* f) { - const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; - upb_StringView name = - google_protobuf_FieldDescriptorProto_type_name(field_proto); - bool has_name = - google_protobuf_FieldDescriptorProto_has_type_name(field_proto); - switch ((int)f->type_) { - case FIELD_TYPE_UNSPECIFIED: { - // Type was not specified and must be inferred. - UPB_ASSERT(has_name); - upb_deftype_t type; - const void* def = - symtab_resolveany(ctx, f->full_name, prefix, name, &type); - switch (type) { - case UPB_DEFTYPE_ENUM: - f->sub.enumdef = def; - f->type_ = kUpb_FieldType_Enum; - break; - case UPB_DEFTYPE_MSG: - f->sub.msgdef = def; - f->type_ = kUpb_FieldType_Message; // It appears there is no way of - // this being a group. - break; - default: - symtab_errf(ctx, "Couldn't resolve type name for field %s", - f->full_name); - } - } - case kUpb_FieldType_Message: - case kUpb_FieldType_Group: - UPB_ASSERT(has_name); - f->sub.msgdef = - symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); - break; - case kUpb_FieldType_Enum: - UPB_ASSERT(has_name); - f->sub.enumdef = - symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_ENUM); - break; - default: - // No resolution necessary. - break; - } -} + upb_value v = _upb_DefType_Pack(o, UPB_DEFTYPE_ONEOF); + bool ok = _upb_MessageDef_Insert(m, name.data, name.size, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); -static void resolve_extension( - symtab_addctx* ctx, const char* prefix, upb_FieldDef* f, - const google_protobuf_FieldDescriptorProto* field_proto) { - if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) { - symtab_errf(ctx, "extension for field '%s' had no extendee", f->full_name); - } + ok = upb_inttable_init(&o->itof, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); - upb_StringView name = - google_protobuf_FieldDescriptorProto_extendee(field_proto); - const upb_MessageDef* m = - symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); - f->msgdef = m; + ok = upb_strtable_init(&o->ntof, 4, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} - bool found = false; +// Allocate and initialize an array of |n| oneof defs. +upb_OneofDef* _upb_OneofDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_OneofDescriptorProto* const* protos, upb_MessageDef* m) { + _upb_DefType_CheckPadding(sizeof(upb_OneofDef)); - for (int i = 0, n = m->ext_range_count; i < n; i++) { - const upb_ExtensionRange* r = &m->ext_ranges[i]; - if (r->start <= f->number_ && f->number_ < r->end) { - found = true; - break; - } + upb_OneofDef* o = _upb_DefBuilder_Alloc(ctx, sizeof(upb_OneofDef) * n); + for (int i = 0; i < n; i++) { + create_oneofdef(ctx, m, protos[i], &o[i]); } + return o; +} - if (!found) { - symtab_errf(ctx, - "field number %u in extension %s has no extension range in " - "message %s", - (unsigned)f->number_, f->full_name, f->msgdef->full_name); - } - const upb_MiniTable_Extension* ext = ctx->file->ext_layouts[f->layout_index]; - if (ctx->layout) { - UPB_ASSERT(upb_FieldDef_Number(f) == ext->field.number); - } else { - upb_MiniTable_Extension* mut_ext = (upb_MiniTable_Extension*)ext; - fill_fieldlayout(&mut_ext->field, f); - mut_ext->field.presence = 0; - mut_ext->field.offset = 0; - mut_ext->field.submsg_index = 0; - mut_ext->extendee = f->msgdef->layout; - mut_ext->sub.submsg = f->sub.msgdef->layout; - } - CHK_OOM(upb_inttable_insert(&ctx->symtab->exts, (uintptr_t)ext, - upb_value_constptr(f), ctx->arena)); +// Must be last. + +struct upb_ServiceDef { + const google_protobuf_ServiceOptions* opts; + const upb_FileDef* file; + const char* full_name; + upb_MethodDef* methods; + int method_count; + int index; +}; + +upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int index) { + return (upb_ServiceDef*)&s[index]; } -static void resolve_default( - symtab_addctx* ctx, upb_FieldDef* f, - const google_protobuf_FieldDescriptorProto* field_proto) { - // Have to delay resolving of the default value until now because of the enum - // case, since enum defaults are specified with a label. - if (google_protobuf_FieldDescriptorProto_has_default_value(field_proto)) { - upb_StringView defaultval = - google_protobuf_FieldDescriptorProto_default_value(field_proto); +const google_protobuf_ServiceOptions* upb_ServiceDef_Options(const upb_ServiceDef* s) { + return s->opts; +} - if (f->file->syntax == kUpb_Syntax_Proto3) { - symtab_errf(ctx, "proto3 fields cannot have explicit defaults (%s)", - f->full_name); - } +bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s) { + return s->opts != (void*)kUpbDefOptDefault; +} - if (upb_FieldDef_IsSubMessage(f)) { - symtab_errf(ctx, "message fields cannot have explicit defaults (%s)", - f->full_name); - } +const char* upb_ServiceDef_FullName(const upb_ServiceDef* s) { + return s->full_name; +} - parse_default(ctx, defaultval.data, defaultval.size, f); - f->has_default = true; - } else { - set_default_default(ctx, f); - f->has_default = false; - } +const char* upb_ServiceDef_Name(const upb_ServiceDef* s) { + return _upb_DefBuilder_FullToShort(s->full_name); } -static void resolve_fielddef(symtab_addctx* ctx, const char* prefix, - upb_FieldDef* f) { - // We have to stash this away since resolve_subdef() may overwrite it. - const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; +int upb_ServiceDef_Index(const upb_ServiceDef* s) { return s->index; } - resolve_subdef(ctx, prefix, f); - resolve_default(ctx, f, field_proto); +const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s) { + return s->file; +} - if (f->is_extension_) { - resolve_extension(ctx, prefix, f, field_proto); - } +int upb_ServiceDef_MethodCount(const upb_ServiceDef* s) { + return s->method_count; } -static void resolve_msgdef(symtab_addctx* ctx, upb_MessageDef* m) { - for (int i = 0; i < m->field_count; i++) { - resolve_fielddef(ctx, m->full_name, (upb_FieldDef*)&m->fields[i]); - } +const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i) { + return (i < 0 || i >= s->method_count) ? NULL + : _upb_MethodDef_At(s->methods, i); +} - m->in_message_set = false; - for (int i = 0; i < m->nested_ext_count; i++) { - upb_FieldDef* ext = (upb_FieldDef*)&m->nested_exts[i]; - resolve_fielddef(ctx, m->full_name, ext); - if (ext->type_ == kUpb_FieldType_Message && - ext->label_ == kUpb_Label_Optional && ext->sub.msgdef == m && - google_protobuf_MessageOptions_message_set_wire_format( - ext->msgdef->opts)) { - m->in_message_set = true; +const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, + const char* name) { + for (int i = 0; i < s->method_count; i++) { + const upb_MethodDef* m = _upb_MethodDef_At(s->methods, i); + if (strcmp(name, upb_MethodDef_Name(m)) == 0) { + return m; } } - - if (!ctx->layout) make_layout(ctx, m); - - for (int i = 0; i < m->nested_msg_count; i++) { - resolve_msgdef(ctx, (upb_MessageDef*)&m->nested_msgs[i]); - } + return NULL; } -static int count_exts_in_msg(const google_protobuf_DescriptorProto* msg_proto) { +static void create_service(upb_DefBuilder* ctx, + const google_protobuf_ServiceDescriptorProto* svc_proto, + upb_ServiceDef* s) { + upb_StringView name; size_t n; - google_protobuf_DescriptorProto_extension(msg_proto, &n); - int ext_count = n; - const google_protobuf_DescriptorProto* const* nested_msgs = - google_protobuf_DescriptorProto_nested_type(msg_proto, &n); - for (size_t i = 0; i < n; i++) { - ext_count += count_exts_in_msg(nested_msgs[i]); - } + // Must happen before _upb_DefBuilder_Add() + s->file = _upb_DefBuilder_File(ctx); - return ext_count; -} + name = google_protobuf_ServiceDescriptorProto_name(svc_proto); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); + const char* package = _upb_FileDef_RawPackage(s->file); + s->full_name = _upb_DefBuilder_MakeFullName(ctx, package, name); + _upb_DefBuilder_Add(ctx, s->full_name, + _upb_DefType_Pack(s, UPB_DEFTYPE_SERVICE)); + + const google_protobuf_MethodDescriptorProto* const* methods = + google_protobuf_ServiceDescriptorProto_method(svc_proto, &n); + s->method_count = n; + s->methods = _upb_MethodDefs_New(ctx, n, methods, s); -static void build_filedef( - symtab_addctx* ctx, upb_FileDef* file, - const google_protobuf_FileDescriptorProto* file_proto) { - const google_protobuf_DescriptorProto* const* msgs; - const google_protobuf_EnumDescriptorProto* const* enums; - const google_protobuf_FieldDescriptorProto* const* exts; - const google_protobuf_ServiceDescriptorProto* const* services; - const upb_StringView* strs; - const int32_t* public_deps; - const int32_t* weak_deps; - size_t i, n; + UBP_DEF_SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, + svc_proto); +} - file->symtab = ctx->symtab; +upb_ServiceDef* _upb_ServiceDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_ServiceDescriptorProto* const* protos) { + _upb_DefType_CheckPadding(sizeof(upb_ServiceDef)); - /* Count all extensions in the file, to build a flat array of layouts. */ - google_protobuf_FileDescriptorProto_extension(file_proto, &n); - int ext_count = n; - msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); + upb_ServiceDef* s = _upb_DefBuilder_Alloc(ctx, sizeof(upb_ServiceDef) * n); for (int i = 0; i < n; i++) { - ext_count += count_exts_in_msg(msgs[i]); + create_service(ctx, protos[i], &s[i]); + s[i].index = i; } - file->ext_count = ext_count; + return s; +} - if (ctx->layout) { - /* We are using the ext layouts that were passed in. */ - file->ext_layouts = ctx->layout->exts; - if (ctx->layout->ext_count != file->ext_count) { - symtab_errf(ctx, "Extension count did not match layout (%d vs %d)", - ctx->layout->ext_count, file->ext_count); - } - } else { - /* We are building ext layouts from scratch. */ - file->ext_layouts = - symtab_alloc(ctx, sizeof(*file->ext_layouts) * file->ext_count); - upb_MiniTable_Extension* ext = - symtab_alloc(ctx, sizeof(*ext) * file->ext_count); - for (int i = 0; i < file->ext_count; i++) { - file->ext_layouts[i] = &ext[i]; - } - } +/* + * upb_table Implementation + * + * Implementation is heavily inspired by Lua's ltable.c. + */ - if (!google_protobuf_FileDescriptorProto_has_name(file_proto)) { - symtab_errf(ctx, "File has no name"); - } - file->name = - strviewdup(ctx, google_protobuf_FileDescriptorProto_name(file_proto)); +#include - if (google_protobuf_FileDescriptorProto_has_package(file_proto)) { - upb_StringView package = - google_protobuf_FileDescriptorProto_package(file_proto); - check_ident(ctx, package, true); - file->package = strviewdup(ctx, package); - } else { - file->package = NULL; - } +// Must be last. - if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) { - upb_StringView syntax = - google_protobuf_FileDescriptorProto_syntax(file_proto); +#define UPB_MAXARRSIZE 16 /* 64k. */ - if (streql_view(syntax, "proto2")) { - file->syntax = kUpb_Syntax_Proto2; - } else if (streql_view(syntax, "proto3")) { - file->syntax = kUpb_Syntax_Proto3; - } else { - symtab_errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", - UPB_STRINGVIEW_ARGS(syntax)); - } - } else { - file->syntax = kUpb_Syntax_Proto2; - } +/* From Chromium. */ +#define ARRAY_SIZE(x) \ + ((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x]))))) - /* Read options. */ - SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); +static const double MAX_LOAD = 0.85; - /* Verify dependencies. */ - strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n); - file->dep_count = n; - file->deps = symtab_alloc(ctx, sizeof(*file->deps) * n); +/* The minimum utilization of the array part of a mixed hash/array table. This + * is a speed/memory-usage tradeoff (though it's not straightforward because of + * cache effects). The lower this is, the more memory we'll use. */ +static const double MIN_DENSITY = 0.1; - for (i = 0; i < n; i++) { - upb_StringView str = strs[i]; - file->deps[i] = - upb_DefPool_FindFileByNameWithSize(ctx->symtab, str.data, str.size); - if (!file->deps[i]) { - symtab_errf(ctx, - "Depends on file '" UPB_STRINGVIEW_FORMAT - "', but it has not been loaded", - UPB_STRINGVIEW_ARGS(str)); - } - } +static bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; } - public_deps = - google_protobuf_FileDescriptorProto_public_dependency(file_proto, &n); - file->public_dep_count = n; - file->public_deps = symtab_alloc(ctx, sizeof(*file->public_deps) * n); - int32_t* mutable_public_deps = (int32_t*)file->public_deps; - for (i = 0; i < n; i++) { - if (public_deps[i] >= file->dep_count) { - symtab_errf(ctx, "public_dep %d is out of range", (int)public_deps[i]); - } - mutable_public_deps[i] = public_deps[i]; - } +static upb_value _upb_value_val(uint64_t val) { + upb_value ret; + _upb_value_setval(&ret, val); + return ret; +} - weak_deps = - google_protobuf_FileDescriptorProto_weak_dependency(file_proto, &n); - file->weak_dep_count = n; - file->weak_deps = symtab_alloc(ctx, sizeof(*file->weak_deps) * n); - int32_t* mutable_weak_deps = (int32_t*)file->weak_deps; - for (i = 0; i < n; i++) { - if (weak_deps[i] >= file->dep_count) { - symtab_errf(ctx, "weak_dep %d is out of range", (int)weak_deps[i]); - } - mutable_weak_deps[i] = weak_deps[i]; - } +static int log2ceil(uint64_t v) { + int ret = 0; + bool pow2 = is_pow2(v); + while (v >>= 1) ret++; + ret = pow2 ? ret : ret + 1; /* Ceiling. */ + return UPB_MIN(UPB_MAXARRSIZE, ret); +} - /* Create enums. */ - enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); - file->top_lvl_enum_count = n; - file->top_lvl_enums = symtab_alloc(ctx, sizeof(*file->top_lvl_enums) * n); - for (i = 0; i < n; i++) { - create_enumdef(ctx, file->package, enums[i], NULL, &file->top_lvl_enums[i]); - } +char* upb_strdup2(const char* s, size_t len, upb_Arena* a) { + size_t n; + char* p; - /* Create extensions. */ - exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n); - file->top_lvl_ext_count = n; - file->top_lvl_exts = symtab_alloc(ctx, sizeof(*file->top_lvl_exts) * n); - for (i = 0; i < n; i++) { - create_fielddef(ctx, file->package, NULL, exts[i], &file->top_lvl_exts[i], - /* is_extension= */ true); - ((upb_FieldDef*)&file->top_lvl_exts[i])->index_ = i; + /* Prevent overflow errors. */ + if (len == SIZE_MAX) return NULL; + /* Always null-terminate, even if binary data; but don't rely on the input to + * have a null-terminating byte since it may be a raw binary buffer. */ + n = len + 1; + p = upb_Arena_Malloc(a, n); + if (p) { + memcpy(p, s, len); + p[len] = 0; } + return p; +} - /* Create messages. */ - msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); - file->top_lvl_msg_count = n; - file->top_lvl_msgs = symtab_alloc(ctx, sizeof(*file->top_lvl_msgs) * n); - for (i = 0; i < n; i++) { - create_msgdef(ctx, file->package, msgs[i], NULL, &file->top_lvl_msgs[i]); - } +/* A type to represent the lookup key of either a strtable or an inttable. */ +typedef union { + uintptr_t num; + struct { + const char* str; + size_t len; + } str; +} lookupkey_t; - /* Create services. */ - services = google_protobuf_FileDescriptorProto_service(file_proto, &n); - file->service_count = n; - file->services = symtab_alloc(ctx, sizeof(*file->services) * n); - for (i = 0; i < n; i++) { - create_service(ctx, services[i], &file->services[i]); - ((upb_ServiceDef*)&file->services[i])->index = i; +static lookupkey_t strkey2(const char* str, size_t len) { + lookupkey_t k; + k.str.str = str; + k.str.len = len; + return k; +} + +static lookupkey_t intkey(uintptr_t key) { + lookupkey_t k; + k.num = key; + return k; +} + +typedef uint32_t hashfunc_t(upb_tabkey key); +typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2); + +/* Base table (shared code) ***************************************************/ + +static uint32_t upb_inthash(uintptr_t key) { return (uint32_t)key; } + +static const upb_tabent* upb_getentry(const upb_table* t, uint32_t hash) { + return t->entries + (hash & t->mask); +} + +static bool upb_arrhas(upb_tabval key) { return key.val != (uint64_t)-1; } + +static bool isfull(upb_table* t) { return t->count == t->max_count; } + +static bool init(upb_table* t, uint8_t size_lg2, upb_Arena* a) { + size_t bytes; + + t->count = 0; + t->size_lg2 = size_lg2; + t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0; + t->max_count = upb_table_size(t) * MAX_LOAD; + bytes = upb_table_size(t) * sizeof(upb_tabent); + if (bytes > 0) { + t->entries = upb_Arena_Malloc(a, bytes); + if (!t->entries) return false; + memset(t->entries, 0, bytes); + } else { + t->entries = NULL; } + return true; +} - /* Now that all names are in the table, build layouts and resolve refs. */ - for (i = 0; i < (size_t)file->top_lvl_ext_count; i++) { - resolve_fielddef(ctx, file->package, (upb_FieldDef*)&file->top_lvl_exts[i]); +static upb_tabent* emptyent(upb_table* t, upb_tabent* e) { + upb_tabent* begin = t->entries; + upb_tabent* end = begin + upb_table_size(t); + for (e = e + 1; e < end; e++) { + if (upb_tabent_isempty(e)) return e; } - - for (i = 0; i < (size_t)file->top_lvl_msg_count; i++) { - resolve_msgdef(ctx, (upb_MessageDef*)&file->top_lvl_msgs[i]); + for (e = begin; e < end; e++) { + if (upb_tabent_isempty(e)) return e; } + UPB_ASSERT(false); + return NULL; +} - if (file->ext_count) { - CHK_OOM(_upb_extreg_add(ctx->symtab->extreg, file->ext_layouts, - file->ext_count)); - } +static upb_tabent* getentry_mutable(upb_table* t, uint32_t hash) { + return (upb_tabent*)upb_getentry(t, hash); } -static void remove_filedef(upb_DefPool* s, upb_FileDef* file) { - intptr_t iter = UPB_INTTABLE_BEGIN; - upb_StringView key; - upb_value val; - while (upb_strtable_next2(&s->syms, &key, &val, &iter)) { - const upb_FileDef* f; - switch (deftype(val)) { - case UPB_DEFTYPE_EXT: - f = upb_FieldDef_File(unpack_def(val, UPB_DEFTYPE_EXT)); - break; - case UPB_DEFTYPE_MSG: - f = upb_MessageDef_File(unpack_def(val, UPB_DEFTYPE_MSG)); - break; - case UPB_DEFTYPE_ENUM: - f = upb_EnumDef_File(unpack_def(val, UPB_DEFTYPE_ENUM)); - break; - case UPB_DEFTYPE_ENUMVAL: - f = upb_EnumDef_File( - upb_EnumValueDef_Enum(unpack_def(val, UPB_DEFTYPE_ENUMVAL))); - break; - case UPB_DEFTYPE_SERVICE: - f = upb_ServiceDef_File(unpack_def(val, UPB_DEFTYPE_SERVICE)); - break; - default: - UPB_UNREACHABLE(); - } +static const upb_tabent* findentry(const upb_table* t, lookupkey_t key, + uint32_t hash, eqlfunc_t* eql) { + const upb_tabent* e; - if (f == file) upb_strtable_removeiter(&s->syms, &iter); + if (t->size_lg2 == 0) return NULL; + e = upb_getentry(t, hash); + if (upb_tabent_isempty(e)) return NULL; + while (1) { + if (eql(e->key, key)) return e; + if ((e = e->next) == NULL) return NULL; } } -static const upb_FileDef* _upb_DefPool_AddFile( - upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, - const upb_MiniTable_File* layout, upb_Status* status) { - symtab_addctx ctx; - upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto); - upb_value v; +static upb_tabent* findentry_mutable(upb_table* t, lookupkey_t key, + uint32_t hash, eqlfunc_t* eql) { + return (upb_tabent*)findentry(t, key, hash, eql); +} - if (upb_strtable_lookup2(&s->files, name.data, name.size, &v)) { - if (unpack_def(v, UPB_DEFTYPE_FILE)) { - upb_Status_SetErrorFormat(status, "duplicate file name (%.*s)", - UPB_STRINGVIEW_ARGS(name)); - return NULL; - } - const upb_MiniTable_File* registered = unpack_def(v, UPB_DEFTYPE_LAYOUT); - UPB_ASSERT(registered); - if (layout && layout != registered) { - upb_Status_SetErrorFormat( - status, "tried to build with a different layout (filename=%.*s)", - UPB_STRINGVIEW_ARGS(name)); - return NULL; +static bool lookup(const upb_table* t, lookupkey_t key, upb_value* v, + uint32_t hash, eqlfunc_t* eql) { + const upb_tabent* e = findentry(t, key, hash, eql); + if (e) { + if (v) { + _upb_value_setval(v, e->val.val); } - layout = registered; + return true; + } else { + return false; } +} - ctx.symtab = s; - ctx.layout = layout; - ctx.msg_count = 0; - ctx.enum_count = 0; - ctx.ext_count = 0; - ctx.status = status; - ctx.file = NULL; - ctx.arena = upb_Arena_New(); - ctx.tmp_arena = upb_Arena_New(); +/* The given key must not already exist in the table. */ +static void insert(upb_table* t, lookupkey_t key, upb_tabkey tabkey, + upb_value val, uint32_t hash, hashfunc_t* hashfunc, + eqlfunc_t* eql) { + upb_tabent* mainpos_e; + upb_tabent* our_e; - if (!ctx.arena || !ctx.tmp_arena) { - if (ctx.arena) upb_Arena_Free(ctx.arena); - if (ctx.tmp_arena) upb_Arena_Free(ctx.tmp_arena); - upb_Status_setoom(status); - return NULL; - } + UPB_ASSERT(findentry(t, key, hash, eql) == NULL); - if (UPB_UNLIKELY(UPB_SETJMP(ctx.err))) { - UPB_ASSERT(!upb_Status_IsOk(status)); - if (ctx.file) { - remove_filedef(s, ctx.file); - ctx.file = NULL; - } + t->count++; + mainpos_e = getentry_mutable(t, hash); + our_e = mainpos_e; + + if (upb_tabent_isempty(mainpos_e)) { + /* Our main position is empty; use it. */ + our_e->next = NULL; } else { - ctx.file = symtab_alloc(&ctx, sizeof(*ctx.file)); - build_filedef(&ctx, ctx.file, file_proto); - upb_strtable_insert(&s->files, name.data, name.size, - pack_def(ctx.file, UPB_DEFTYPE_FILE), ctx.arena); - UPB_ASSERT(upb_Status_IsOk(status)); - upb_Arena_Fuse(s->arena, ctx.arena); + /* Collision. */ + upb_tabent* new_e = emptyent(t, mainpos_e); + /* Head of collider's chain. */ + upb_tabent* chain = getentry_mutable(t, hashfunc(mainpos_e->key)); + if (chain == mainpos_e) { + /* Existing ent is in its main position (it has the same hash as us, and + * is the head of our chain). Insert to new ent and append to this chain. + */ + new_e->next = mainpos_e->next; + mainpos_e->next = new_e; + our_e = new_e; + } else { + /* Existing ent is not in its main position (it is a node in some other + * chain). This implies that no existing ent in the table has our hash. + * Evict it (updating its chain) and use its ent for head of our chain. */ + *new_e = *mainpos_e; /* copies next. */ + while (chain->next != mainpos_e) { + chain = (upb_tabent*)chain->next; + UPB_ASSERT(chain); + } + chain->next = new_e; + our_e = mainpos_e; + our_e->next = NULL; + } } - - upb_Arena_Free(ctx.arena); - upb_Arena_Free(ctx.tmp_arena); - return ctx.file; + our_e->key = tabkey; + our_e->val.val = val.val; + UPB_ASSERT(findentry(t, key, hash, eql) == our_e); } -const upb_FileDef* upb_DefPool_AddFile( - upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, - upb_Status* status) { - return _upb_DefPool_AddFile(s, file_proto, NULL, status); +static bool rm(upb_table* t, lookupkey_t key, upb_value* val, + upb_tabkey* removed, uint32_t hash, eqlfunc_t* eql) { + upb_tabent* chain = getentry_mutable(t, hash); + if (upb_tabent_isempty(chain)) return false; + if (eql(chain->key, key)) { + /* Element to remove is at the head of its chain. */ + t->count--; + if (val) _upb_value_setval(val, chain->val.val); + if (removed) *removed = chain->key; + if (chain->next) { + upb_tabent* move = (upb_tabent*)chain->next; + *chain = *move; + move->key = 0; /* Make the slot empty. */ + } else { + chain->key = 0; /* Make the slot empty. */ + } + return true; + } else { + /* Element to remove is either in a non-head position or not in the + * table. */ + while (chain->next && !eql(chain->next->key, key)) { + chain = (upb_tabent*)chain->next; + } + if (chain->next) { + /* Found element to remove. */ + upb_tabent* rm = (upb_tabent*)chain->next; + t->count--; + if (val) _upb_value_setval(val, chain->next->val.val); + if (removed) *removed = rm->key; + rm->key = 0; /* Make the slot empty. */ + chain->next = rm->next; + return true; + } else { + /* Element to remove is not in the table. */ + return false; + } + } } -/* Include here since we want most of this file to be stdio-free. */ -#include +static size_t next(const upb_table* t, size_t i) { + do { + if (++i >= upb_table_size(t)) return SIZE_MAX - 1; /* Distinct from -1. */ + } while (upb_tabent_isempty(&t->entries[i])); -bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, - bool rebuild_minitable) { - /* Since this function should never fail (it would indicate a bug in upb) we - * print errors to stderr instead of returning error status to the user. */ - _upb_DefPool_Init** deps = init->deps; - google_protobuf_FileDescriptorProto* file; - upb_Arena* arena; - upb_Status status; + return i; +} - upb_Status_Clear(&status); +static size_t begin(const upb_table* t) { return next(t, -1); } - if (upb_DefPool_FindFileByName(s, init->filename)) { - return true; - } +/* upb_strtable ***************************************************************/ - arena = upb_Arena_New(); +/* A simple "subclass" of upb_table that only adds a hash function for strings. + */ - for (; *deps; deps++) { - if (!_upb_DefPool_LoadDefInitEx(s, *deps, rebuild_minitable)) goto err; - } +static upb_tabkey strcopy(lookupkey_t k2, upb_Arena* a) { + uint32_t len = (uint32_t)k2.str.len; + char* str = upb_Arena_Malloc(a, k2.str.len + sizeof(uint32_t) + 1); + if (str == NULL) return 0; + memcpy(str, &len, sizeof(uint32_t)); + if (k2.str.len) memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len); + str[sizeof(uint32_t) + k2.str.len] = '\0'; + return (uintptr_t)str; +} - file = google_protobuf_FileDescriptorProto_parse_ex( - init->descriptor.data, init->descriptor.size, NULL, - kUpb_DecodeOption_AliasString, arena); - s->bytes_loaded += init->descriptor.size; +/* Adapted from ABSL's wyhash. */ - if (!file) { - upb_Status_SetErrorFormat( - &status, - "Failed to parse compiled-in descriptor for file '%s'. This should " - "never happen.", - init->filename); - goto err; - } +static uint64_t UnalignedLoad64(const void* p) { + uint64_t val; + memcpy(&val, p, 8); + return val; +} - const upb_MiniTable_File* mt = rebuild_minitable ? NULL : init->layout; - if (!_upb_DefPool_AddFile(s, file, mt, &status)) { - goto err; - } +static uint32_t UnalignedLoad32(const void* p) { + uint32_t val; + memcpy(&val, p, 4); + return val; +} - upb_Arena_Free(arena); - return true; +#if defined(_MSC_VER) && defined(_M_X64) +#include +#endif -err: - fprintf(stderr, - "Error loading compiled-in descriptor for file '%s' (this should " - "never happen): %s\n", - init->filename, upb_Status_ErrorMessage(&status)); - upb_Arena_Free(arena); - return false; +/* Computes a * b, returning the low 64 bits of the result and storing the high + * 64 bits in |*high|. */ +static uint64_t upb_umul128(uint64_t v0, uint64_t v1, uint64_t* out_high) { +#ifdef __SIZEOF_INT128__ + __uint128_t p = v0; + p *= v1; + *out_high = (uint64_t)(p >> 64); + return (uint64_t)p; +#elif defined(_MSC_VER) && defined(_M_X64) + return _umul128(v0, v1, out_high); +#else + uint64_t a32 = v0 >> 32; + uint64_t a00 = v0 & 0xffffffff; + uint64_t b32 = v1 >> 32; + uint64_t b00 = v1 & 0xffffffff; + uint64_t high = a32 * b32; + uint64_t low = a00 * b00; + uint64_t mid1 = a32 * b00; + uint64_t mid2 = a00 * b32; + low += (mid1 << 32) + (mid2 << 32); + // Omit carry bit, for mixing we do not care about exact numerical precision. + high += (mid1 >> 32) + (mid2 >> 32); + *out_high = high; + return low; +#endif } -size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s) { - return s->bytes_loaded; +static uint64_t WyhashMix(uint64_t v0, uint64_t v1) { + uint64_t high; + uint64_t low = upb_umul128(v0, v1, &high); + return low ^ high; } -upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s) { return s->arena; } +static uint64_t Wyhash(const void* data, size_t len, uint64_t seed, + const uint64_t salt[]) { + const uint8_t* ptr = (const uint8_t*)data; + uint64_t starting_length = (uint64_t)len; + uint64_t current_state = seed ^ salt[0]; -const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable( - const upb_DefPool* s, const upb_MiniTable_Extension* ext) { - upb_value v; - bool ok = upb_inttable_lookup(&s->exts, (uintptr_t)ext, &v); - UPB_ASSERT(ok); - return upb_value_getconstptr(v); -} + if (len > 64) { + // If we have more than 64 bytes, we're going to handle chunks of 64 + // bytes at a time. We're going to build up two separate hash states + // which we will then hash together. + uint64_t duplicated_state = current_state; -const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, - const upb_MessageDef* m, - int32_t fieldnum) { - const upb_MiniTable* l = upb_MessageDef_MiniTable(m); - const upb_MiniTable_Extension* ext = _upb_extreg_get(s->extreg, l, fieldnum); - return ext ? _upb_DefPool_FindExtensionByMiniTable(s, ext) : NULL; -} + do { + uint64_t a = UnalignedLoad64(ptr); + uint64_t b = UnalignedLoad64(ptr + 8); + uint64_t c = UnalignedLoad64(ptr + 16); + uint64_t d = UnalignedLoad64(ptr + 24); + uint64_t e = UnalignedLoad64(ptr + 32); + uint64_t f = UnalignedLoad64(ptr + 40); + uint64_t g = UnalignedLoad64(ptr + 48); + uint64_t h = UnalignedLoad64(ptr + 56); -bool _upb_DefPool_registerlayout(upb_DefPool* s, const char* filename, - const upb_MiniTable_File* file) { - if (upb_DefPool_FindFileByName(s, filename)) return false; - upb_value v = pack_def(file, UPB_DEFTYPE_LAYOUT); - return upb_strtable_insert(&s->files, filename, strlen(filename), v, - s->arena); -} + uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state); + uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state); + current_state = (cs0 ^ cs1); -const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( - const upb_DefPool* s) { - return s->extreg; -} + uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state); + uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state); + duplicated_state = (ds0 ^ ds1); -const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, - const upb_MessageDef* m, - size_t* count) { - size_t n = 0; - intptr_t iter = UPB_INTTABLE_BEGIN; - uintptr_t key; - upb_value val; - // This is O(all exts) instead of O(exts for m). If we need this to be - // efficient we may need to make extreg into a two-level table, or have a - // second per-message index. - while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { - const upb_FieldDef* f = upb_value_getconstptr(val); - if (upb_FieldDef_ContainingType(f) == m) n++; - } - const upb_FieldDef** exts = malloc(n * sizeof(*exts)); - iter = UPB_INTTABLE_BEGIN; - size_t i = 0; - while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { - const upb_FieldDef* f = upb_value_getconstptr(val); - if (upb_FieldDef_ContainingType(f) == m) exts[i++] = f; + ptr += 64; + len -= 64; + } while (len > 64); + + current_state = current_state ^ duplicated_state; } - *count = n; - return exts; -} -#undef CHK_OOM + // We now have a data `ptr` with at most 64 bytes and the current state + // of the hashing state machine stored in current_state. + while (len > 16) { + uint64_t a = UnalignedLoad64(ptr); + uint64_t b = UnalignedLoad64(ptr + 8); -/** upb/reflection.c ************************************************************/ + current_state = WyhashMix(a ^ salt[1], b ^ current_state); -#include + ptr += 16; + len -= 16; + } + // We now have a data `ptr` with at most 16 bytes. + uint64_t a = 0; + uint64_t b = 0; + if (len > 8) { + // When we have at least 9 and at most 16 bytes, set A to the first 64 + // bits of the input and B to the last 64 bits of the input. Yes, they will + // overlap in the middle if we are working with less than the full 16 + // bytes. + a = UnalignedLoad64(ptr); + b = UnalignedLoad64(ptr + len - 8); + } else if (len > 3) { + // If we have at least 4 and at most 8 bytes, set A to the first 32 + // bits and B to the last 32 bits. + a = UnalignedLoad32(ptr); + b = UnalignedLoad32(ptr + len - 4); + } else if (len > 0) { + // If we have at least 1 and at most 3 bytes, read all of the provided + // bits into A, with some adjustments. + a = ((ptr[0] << 16) | (ptr[len >> 1] << 8) | ptr[len - 1]); + b = 0; + } else { + a = 0; + b = 0; + } -static size_t get_field_size(const upb_MiniTable_Field* f) { - static unsigned char sizes[] = { - 0, /* 0 */ - 8, /* kUpb_FieldType_Double */ - 4, /* kUpb_FieldType_Float */ - 8, /* kUpb_FieldType_Int64 */ - 8, /* kUpb_FieldType_UInt64 */ - 4, /* kUpb_FieldType_Int32 */ - 8, /* kUpb_FieldType_Fixed64 */ - 4, /* kUpb_FieldType_Fixed32 */ - 1, /* kUpb_FieldType_Bool */ - sizeof(upb_StringView), /* kUpb_FieldType_String */ - sizeof(void*), /* kUpb_FieldType_Group */ - sizeof(void*), /* kUpb_FieldType_Message */ - sizeof(upb_StringView), /* kUpb_FieldType_Bytes */ - 4, /* kUpb_FieldType_UInt32 */ - 4, /* kUpb_FieldType_Enum */ - 4, /* kUpb_FieldType_SFixed32 */ - 8, /* kUpb_FieldType_SFixed64 */ - 4, /* kUpb_FieldType_SInt32 */ - 8, /* kUpb_FieldType_SInt64 */ - }; - return upb_IsRepeatedOrMap(f) ? sizeof(void*) : sizes[f->descriptortype]; + uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state); + uint64_t z = salt[1] ^ starting_length; + return WyhashMix(w, z); } -/* Strings/bytes are special-cased in maps. */ -static char _upb_CTypeo_mapsize[12] = { - 0, - 1, /* kUpb_CType_Bool */ - 4, /* kUpb_CType_Float */ - 4, /* kUpb_CType_Int32 */ - 4, /* kUpb_CType_UInt32 */ - 4, /* kUpb_CType_Enum */ - sizeof(void*), /* kUpb_CType_Message */ - 8, /* kUpb_CType_Double */ - 8, /* kUpb_CType_Int64 */ - 8, /* kUpb_CType_UInt64 */ - 0, /* kUpb_CType_String */ - 0, /* kUpb_CType_Bytes */ -}; - -static const char _upb_CTypeo_sizelg2[12] = { - 0, - 0, /* kUpb_CType_Bool */ - 2, /* kUpb_CType_Float */ - 2, /* kUpb_CType_Int32 */ - 2, /* kUpb_CType_UInt32 */ - 2, /* kUpb_CType_Enum */ - UPB_SIZE(2, 3), /* kUpb_CType_Message */ - 3, /* kUpb_CType_Double */ - 3, /* kUpb_CType_Int64 */ - 3, /* kUpb_CType_UInt64 */ - UPB_SIZE(3, 4), /* kUpb_CType_String */ - UPB_SIZE(3, 4), /* kUpb_CType_Bytes */ +const uint64_t kWyhashSalt[5] = { + 0x243F6A8885A308D3ULL, 0x13198A2E03707344ULL, 0xA4093822299F31D0ULL, + 0x082EFA98EC4E6C89ULL, 0x452821E638D01377ULL, }; -/** upb_Message - * *******************************************************************/ - -upb_Message* upb_Message_New(const upb_MessageDef* m, upb_Arena* a) { - return _upb_Message_New(upb_MessageDef_MiniTable(m), a); +uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed) { + return Wyhash(p, n, seed, kWyhashSalt); } -static bool in_oneof(const upb_MiniTable_Field* field) { - return field->presence < 0; +static uint32_t _upb_Hash_NoSeed(const char* p, size_t n) { + return _upb_Hash(p, n, 0); } -static upb_MessageValue _upb_Message_Getraw(const upb_Message* msg, - const upb_FieldDef* f) { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - const char* mem = UPB_PTR_AT(msg, field->offset, char); - upb_MessageValue val = {0}; - memcpy(&val, mem, get_field_size(field)); - return val; +static uint32_t strhash(upb_tabkey key) { + uint32_t len; + char* str = upb_tabstr(key, &len); + return _upb_Hash_NoSeed(str, len); } -bool upb_Message_Has(const upb_Message* msg, const upb_FieldDef* f) { - assert(upb_FieldDef_HasPresence(f)); - if (upb_FieldDef_IsExtension(f)) { - const upb_MiniTable_Extension* ext = _upb_FieldDef_ExtensionMiniTable(f); - return _upb_Message_Getext(msg, ext) != NULL; - } else { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - if (in_oneof(field)) { - return _upb_getoneofcase_field(msg, field) == field->number; - } else if (field->presence > 0) { - return _upb_hasbit_field(msg, field); - } else { - UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message || - field->descriptortype == kUpb_FieldType_Group); - return _upb_Message_Getraw(msg, f).msg_val != NULL; - } - } +static bool streql(upb_tabkey k1, lookupkey_t k2) { + uint32_t len; + char* str = upb_tabstr(k1, &len); + return len == k2.str.len && (len == 0 || memcmp(str, k2.str.str, len) == 0); } -const upb_FieldDef* upb_Message_WhichOneof(const upb_Message* msg, - const upb_OneofDef* o) { - const upb_FieldDef* f = upb_OneofDef_Field(o, 0); - if (upb_OneofDef_IsSynthetic(o)) { - UPB_ASSERT(upb_OneofDef_FieldCount(o) == 1); - return upb_Message_Has(msg, f) ? f : NULL; - } else { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - uint32_t oneof_case = _upb_getoneofcase_field(msg, field); - f = oneof_case ? upb_OneofDef_LookupNumber(o, oneof_case) : NULL; - UPB_ASSERT((f != NULL) == (oneof_case != 0)); - return f; - } +bool upb_strtable_init(upb_strtable* t, size_t expected_size, upb_Arena* a) { + // Multiply by approximate reciprocal of MAX_LOAD (0.85), with pow2 + // denominator. + size_t need_entries = (expected_size + 1) * 1204 / 1024; + UPB_ASSERT(need_entries >= expected_size * 0.85); + int size_lg2 = _upb_Log2Ceiling(need_entries); + return init(&t->t, size_lg2, a); } -upb_MessageValue upb_Message_Get(const upb_Message* msg, - const upb_FieldDef* f) { - if (upb_FieldDef_IsExtension(f)) { - const upb_Message_Extension* ext = - _upb_Message_Getext(msg, _upb_FieldDef_ExtensionMiniTable(f)); - if (ext) { - upb_MessageValue val; - memcpy(&val, &ext->data, sizeof(val)); - return val; - } else if (upb_FieldDef_IsRepeated(f)) { - return (upb_MessageValue){.array_val = NULL}; - } - } else if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) { - return _upb_Message_Getraw(msg, f); - } - return upb_FieldDef_Default(f); +void upb_strtable_clear(upb_strtable* t) { + size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent); + t->t.count = 0; + memset((char*)t->t.entries, 0, bytes); } -upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, - const upb_FieldDef* f, - upb_Arena* a) { - UPB_ASSERT(upb_FieldDef_IsSubMessage(f) || upb_FieldDef_IsRepeated(f)); - if (upb_FieldDef_HasPresence(f) && !upb_Message_Has(msg, f)) { - // We need to skip the upb_Message_Get() call in this case. - goto make; - } +bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a) { + upb_strtable new_table; + upb_strtable_iter i; - upb_MessageValue val = upb_Message_Get(msg, f); - if (val.array_val) { - return (upb_MutableMessageValue){.array = (upb_Array*)val.array_val}; + if (!init(&new_table.t, size_lg2, a)) return false; + upb_strtable_begin(&i, t); + for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { + upb_StringView key = upb_strtable_iter_key(&i); + upb_strtable_insert(&new_table, key.data, key.size, + upb_strtable_iter_value(&i), a); } + *t = new_table; + return true; +} - upb_MutableMessageValue ret; -make: - if (!a) return (upb_MutableMessageValue){.array = NULL}; - if (upb_FieldDef_IsMap(f)) { - const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); - const upb_FieldDef* key = - upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_KeyFieldNumber); - const upb_FieldDef* value = - upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_ValueFieldNumber); - ret.map = - upb_Map_New(a, upb_FieldDef_CType(key), upb_FieldDef_CType(value)); - } else if (upb_FieldDef_IsRepeated(f)) { - ret.array = upb_Array_New(a, upb_FieldDef_CType(f)); - } else { - UPB_ASSERT(upb_FieldDef_IsSubMessage(f)); - ret.msg = upb_Message_New(upb_FieldDef_MessageSubDef(f), a); +bool upb_strtable_insert(upb_strtable* t, const char* k, size_t len, + upb_value v, upb_Arena* a) { + lookupkey_t key; + upb_tabkey tabkey; + uint32_t hash; + + if (isfull(&t->t)) { + /* Need to resize. New table of double the size, add old elements to it. */ + if (!upb_strtable_resize(t, t->t.size_lg2 + 1, a)) { + return false; + } } - val.array_val = ret.array; - upb_Message_Set(msg, f, val, a); + key = strkey2(k, len); + tabkey = strcopy(key, a); + if (tabkey == 0) return false; - return ret; + hash = _upb_Hash_NoSeed(key.str.str, key.str.len); + insert(&t->t, key, tabkey, v, hash, &strhash, &streql); + return true; } -bool upb_Message_Set(upb_Message* msg, const upb_FieldDef* f, - upb_MessageValue val, upb_Arena* a) { - if (upb_FieldDef_IsExtension(f)) { - upb_Message_Extension* ext = _upb_Message_Getorcreateext( - msg, _upb_FieldDef_ExtensionMiniTable(f), a); - if (!ext) return false; - memcpy(&ext->data, &val, sizeof(val)); - } else { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - char* mem = UPB_PTR_AT(msg, field->offset, char); - memcpy(mem, &val, get_field_size(field)); - if (field->presence > 0) { - _upb_sethas_field(msg, field); - } else if (in_oneof(field)) { - *_upb_oneofcase_field(msg, field) = field->number; - } - } - return true; +bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, + upb_value* v) { + uint32_t hash = _upb_Hash_NoSeed(key, len); + return lookup(&t->t, strkey2(key, len), v, hash, &streql); } -void upb_Message_ClearField(upb_Message* msg, const upb_FieldDef* f) { - if (upb_FieldDef_IsExtension(f)) { - _upb_Message_Clearext(msg, _upb_FieldDef_ExtensionMiniTable(f)); - } else { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - char* mem = UPB_PTR_AT(msg, field->offset, char); +bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, + upb_value* val) { + uint32_t hash = _upb_Hash_NoSeed(key, len); + upb_tabkey tabkey; + return rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql); +} - if (field->presence > 0) { - _upb_clearhas_field(msg, field); - } else if (in_oneof(field)) { - uint32_t* oneof_case = _upb_oneofcase_field(msg, field); - if (*oneof_case != field->number) return; - *oneof_case = 0; - } +/* Iteration */ - memset(mem, 0, get_field_size(field)); - } +void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t) { + i->t = t; + i->index = begin(&t->t); } -void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m) { - _upb_Message_Clear(msg, upb_MessageDef_MiniTable(m)); +void upb_strtable_next(upb_strtable_iter* i) { + i->index = next(&i->t->t, i->index); } -bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, - const upb_DefPool* ext_pool, const upb_FieldDef** out_f, - upb_MessageValue* out_val, size_t* iter) { - size_t i = *iter; - size_t n = upb_MessageDef_FieldCount(m); - const upb_MessageValue zero = {0}; - UPB_UNUSED(ext_pool); +bool upb_strtable_done(const upb_strtable_iter* i) { + if (!i->t) return true; + return i->index >= upb_table_size(&i->t->t) || + upb_tabent_isempty(str_tabent(i)); +} - /* Iterate over normal fields, returning the first one that is set. */ - while (++i < n) { - const upb_FieldDef* f = upb_MessageDef_Field(m, i); - upb_MessageValue val = _upb_Message_Getraw(msg, f); +upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i) { + upb_StringView key; + uint32_t len; + UPB_ASSERT(!upb_strtable_done(i)); + key.data = upb_tabstr(str_tabent(i)->key, &len); + key.size = len; + return key; +} - /* Skip field if unset or empty. */ - if (upb_FieldDef_HasPresence(f)) { - if (!upb_Message_Has(msg, f)) continue; - } else { - upb_MessageValue test = val; - if (upb_FieldDef_IsString(f) && !upb_FieldDef_IsRepeated(f)) { - /* Clear string pointer, only size matters (ptr could be non-NULL). */ - test.str_val.data = NULL; - } - /* Continue if NULL or 0. */ - if (memcmp(&test, &zero, sizeof(test)) == 0) continue; +upb_value upb_strtable_iter_value(const upb_strtable_iter* i) { + UPB_ASSERT(!upb_strtable_done(i)); + return _upb_value_val(str_tabent(i)->val.val); +} - /* Continue on empty array or map. */ - if (upb_FieldDef_IsMap(f)) { - if (upb_Map_Size(test.map_val) == 0) continue; - } else if (upb_FieldDef_IsRepeated(f)) { - if (upb_Array_Size(test.array_val) == 0) continue; - } - } +void upb_strtable_iter_setdone(upb_strtable_iter* i) { + i->t = NULL; + i->index = SIZE_MAX; +} - *out_val = val; - *out_f = f; - *iter = i; - return true; - } +bool upb_strtable_iter_isequal(const upb_strtable_iter* i1, + const upb_strtable_iter* i2) { + if (upb_strtable_done(i1) && upb_strtable_done(i2)) return true; + return i1->t == i2->t && i1->index == i2->index; +} - if (ext_pool) { - /* Return any extensions that are set. */ - size_t count; - const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &count); - if (i - n < count) { - ext += count - 1 - (i - n); - memcpy(out_val, &ext->data, sizeof(*out_val)); - *out_f = _upb_DefPool_FindExtensionByMiniTable(ext_pool, ext->ext); - *iter = i; - return true; - } - } +/* upb_inttable ***************************************************************/ - *iter = i; - return false; -} +/* For inttables we use a hybrid structure where small keys are kept in an + * array and large keys are put in the hash table. */ -bool _upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, - int depth) { - size_t iter = kUpb_Message_Begin; - const upb_FieldDef* f; - upb_MessageValue val; - bool ret = true; +static uint32_t inthash(upb_tabkey key) { return upb_inthash(key); } - if (--depth == 0) return false; +static bool inteql(upb_tabkey k1, lookupkey_t k2) { return k1 == k2.num; } - _upb_Message_DiscardUnknown_shallow(msg); +static upb_tabval* mutable_array(upb_inttable* t) { + return (upb_tabval*)t->array; +} - while (upb_Message_Next(msg, m, NULL /*ext_pool*/, &f, &val, &iter)) { - const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); - if (!subm) continue; - if (upb_FieldDef_IsMap(f)) { - const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(subm, 2); - const upb_MessageDef* val_m = upb_FieldDef_MessageSubDef(val_f); - upb_Map* map = (upb_Map*)val.map_val; - size_t iter = kUpb_Map_Begin; +static upb_tabval* inttable_val(upb_inttable* t, uintptr_t key) { + if (key < t->array_size) { + return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL; + } else { + upb_tabent* e = + findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql); + return e ? &e->val : NULL; + } +} - if (!val_m) continue; +static const upb_tabval* inttable_val_const(const upb_inttable* t, + uintptr_t key) { + return inttable_val((upb_inttable*)t, key); +} - while (upb_MapIterator_Next(map, &iter)) { - upb_MessageValue map_val = upb_MapIterator_Value(map, iter); - if (!_upb_Message_DiscardUnknown((upb_Message*)map_val.msg_val, val_m, - depth)) { - ret = false; - } - } - } else if (upb_FieldDef_IsRepeated(f)) { - const upb_Array* arr = val.array_val; - size_t i, n = upb_Array_Size(arr); - for (i = 0; i < n; i++) { - upb_MessageValue elem = upb_Array_Get(arr, i); - if (!_upb_Message_DiscardUnknown((upb_Message*)elem.msg_val, subm, - depth)) { - ret = false; - } - } - } else { - if (!_upb_Message_DiscardUnknown((upb_Message*)val.msg_val, subm, - depth)) { - ret = false; - } +size_t upb_inttable_count(const upb_inttable* t) { + return t->t.count + t->array_count; +} + +static void check(upb_inttable* t) { + UPB_UNUSED(t); +#if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG) + { + /* This check is very expensive (makes inserts/deletes O(N)). */ + size_t count = 0; + upb_inttable_iter i; + upb_inttable_begin(&i, t); + for (; !upb_inttable_done(&i); upb_inttable_next(&i), count++) { + UPB_ASSERT(upb_inttable_lookup(t, upb_inttable_iter_key(&i), NULL)); } + UPB_ASSERT(count == upb_inttable_count(t)); } +#endif +} - return ret; +bool upb_inttable_sizedinit(upb_inttable* t, size_t asize, int hsize_lg2, + upb_Arena* a) { + size_t array_bytes; + + if (!init(&t->t, hsize_lg2, a)) return false; + /* Always make the array part at least 1 long, so that we know key 0 + * won't be in the hash part, which simplifies things. */ + t->array_size = UPB_MAX(1, asize); + t->array_count = 0; + array_bytes = t->array_size * sizeof(upb_value); + t->array = upb_Arena_Malloc(a, array_bytes); + if (!t->array) { + return false; + } + memset(mutable_array(t), 0xff, array_bytes); + check(t); + return true; } -bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, - int maxdepth) { - return _upb_Message_DiscardUnknown(msg, m, maxdepth); +bool upb_inttable_init(upb_inttable* t, upb_Arena* a) { + return upb_inttable_sizedinit(t, 0, 4, a); } -/** upb_Array *****************************************************************/ +bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, + upb_Arena* a) { + upb_tabval tabval; + tabval.val = val.val; + UPB_ASSERT( + upb_arrhas(tabval)); /* This will reject (uint64_t)-1. Fix this. */ -upb_Array* upb_Array_New(upb_Arena* a, upb_CType type) { - return _upb_Array_New(a, 4, _upb_CTypeo_sizelg2[type]); -} + if (key < t->array_size) { + UPB_ASSERT(!upb_arrhas(t->array[key])); + t->array_count++; + mutable_array(t)[key].val = val.val; + } else { + if (isfull(&t->t)) { + /* Need to resize the hash part, but we re-use the array part. */ + size_t i; + upb_table new_table; -size_t upb_Array_Size(const upb_Array* arr) { return arr->len; } + if (!init(&new_table, t->t.size_lg2 + 1, a)) { + return false; + } -upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i) { - upb_MessageValue ret; - const char* data = _upb_array_constptr(arr); - int lg2 = arr->data & 7; - UPB_ASSERT(i < arr->len); - memcpy(&ret, data + (i << lg2), 1 << lg2); - return ret; -} + for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) { + const upb_tabent* e = &t->t.entries[i]; + uint32_t hash; + upb_value v; -void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) { - char* data = _upb_array_ptr(arr); - int lg2 = arr->data & 7; - UPB_ASSERT(i < arr->len); - memcpy(data + (i << lg2), &val, 1 << lg2); -} + _upb_value_setval(&v, e->val.val); + hash = upb_inthash(e->key); + insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql); + } -bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) { - if (!upb_Array_Resize(arr, arr->len + 1, arena)) { - return false; + UPB_ASSERT(t->t.count == new_table.count); + + t->t = new_table; + } + insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql); } - upb_Array_Set(arr, arr->len - 1, val); + check(t); return true; } -void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx, - size_t count) { - char* data = _upb_array_ptr(arr); - int lg2 = arr->data & 7; - memmove(&data[dst_idx << lg2], &data[src_idx << lg2], count << lg2); +bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v) { + const upb_tabval* table_v = inttable_val_const(t, key); + if (!table_v) return false; + if (v) _upb_value_setval(v, table_v->val); + return true; } -bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count, - upb_Arena* arena) { - UPB_ASSERT(i <= arr->len); - UPB_ASSERT(count + arr->len >= count); - size_t oldsize = arr->len; - if (!upb_Array_Resize(arr, arr->len + count, arena)) { - return false; - } - upb_Array_Move(arr, i + count, i, oldsize - i); +bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val) { + upb_tabval* table_v = inttable_val(t, key); + if (!table_v) return false; + table_v->val = val.val; return true; } -/* - * i end arr->len - * |------------|XXXXXXXX|--------| - */ -void upb_Array_Delete(upb_Array* arr, size_t i, size_t count) { - size_t end = i + count; - UPB_ASSERT(i <= end); - UPB_ASSERT(end <= arr->len); - upb_Array_Move(arr, i, end, arr->len - end); - arr->len -= count; +bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val) { + bool success; + if (key < t->array_size) { + if (upb_arrhas(t->array[key])) { + upb_tabval empty = UPB_TABVALUE_EMPTY_INIT; + t->array_count--; + if (val) { + _upb_value_setval(val, t->array[key].val); + } + mutable_array(t)[key] = empty; + success = true; + } else { + success = false; + } + } else { + success = rm(&t->t, intkey(key), val, NULL, upb_inthash(key), &inteql); + } + check(t); + return success; } -bool upb_Array_Resize(upb_Array* arr, size_t size, upb_Arena* arena) { - return _upb_Array_Resize(arr, size, arena); -} +void upb_inttable_compact(upb_inttable* t, upb_Arena* a) { + /* A power-of-two histogram of the table keys. */ + size_t counts[UPB_MAXARRSIZE + 1] = {0}; -/** upb_Map *******************************************************************/ + /* The max key in each bucket. */ + uintptr_t max[UPB_MAXARRSIZE + 1] = {0}; -upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type) { - return _upb_Map_New(a, _upb_CTypeo_mapsize[key_type], - _upb_CTypeo_mapsize[value_type]); -} + upb_inttable_iter i; + size_t arr_count; + int size_lg2; + upb_inttable new_t; -size_t upb_Map_Size(const upb_Map* map) { return _upb_Map_Size(map); } + upb_inttable_begin(&i, t); + for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { + uintptr_t key = upb_inttable_iter_key(&i); + int bucket = log2ceil(key); + max[bucket] = UPB_MAX(max[bucket], key); + counts[bucket]++; + } -bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, - upb_MessageValue* val) { - return _upb_Map_Get(map, &key, map->key_size, val, map->val_size); -} + /* Find the largest power of two that satisfies the MIN_DENSITY + * definition (while actually having some keys). */ + arr_count = upb_inttable_count(t); -void upb_Map_Clear(upb_Map* map) { _upb_Map_Clear(map); } + for (size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 0; size_lg2--) { + if (counts[size_lg2] == 0) { + /* We can halve again without losing any entries. */ + continue; + } else if (arr_count >= (1 << size_lg2) * MIN_DENSITY) { + break; + } -bool upb_Map_Set(upb_Map* map, upb_MessageValue key, upb_MessageValue val, - upb_Arena* arena) { - return _upb_Map_Set(map, &key, map->key_size, &val, map->val_size, arena); -} + arr_count -= counts[size_lg2]; + } -bool upb_Map_Delete(upb_Map* map, upb_MessageValue key) { - return _upb_Map_Delete(map, &key, map->key_size); -} + UPB_ASSERT(arr_count <= upb_inttable_count(t)); -bool upb_MapIterator_Next(const upb_Map* map, size_t* iter) { - return _upb_map_next(map, iter); -} + { + /* Insert all elements into new, perfectly-sized table. */ + size_t arr_size = max[size_lg2] + 1; /* +1 so arr[max] will fit. */ + size_t hash_count = upb_inttable_count(t) - arr_count; + size_t hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0; + int hashsize_lg2 = log2ceil(hash_size); -bool upb_MapIterator_Done(const upb_Map* map, size_t iter) { - upb_strtable_iter i; - UPB_ASSERT(iter != kUpb_Map_Begin); - i.t = &map->table; - i.index = iter; - return upb_strtable_done(&i); + upb_inttable_sizedinit(&new_t, arr_size, hashsize_lg2, a); + upb_inttable_begin(&i, t); + for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { + uintptr_t k = upb_inttable_iter_key(&i); + upb_inttable_insert(&new_t, k, upb_inttable_iter_value(&i), a); + } + UPB_ASSERT(new_t.array_size == arr_size); + UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2); + } + *t = new_t; } -/* Returns the key and value for this entry of the map. */ -upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter) { - upb_strtable_iter i; - upb_MessageValue ret; - i.t = &map->table; - i.index = iter; - _upb_map_fromkey(upb_strtable_iter_key(&i), &ret, map->key_size); - return ret; -} +/* Iteration. */ -upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter) { - upb_strtable_iter i; - upb_MessageValue ret; - i.t = &map->table; - i.index = iter; - _upb_map_fromvalue(upb_strtable_iter_value(&i), &ret, map->val_size); - return ret; +static const upb_tabent* int_tabent(const upb_inttable_iter* i) { + UPB_ASSERT(!i->array_part); + return &i->t->t.entries[i->index]; } -/* void upb_MapIterator_SetValue(upb_Map *map, size_t iter, upb_MessageValue - * value); */ +static upb_tabval int_arrent(const upb_inttable_iter* i) { + UPB_ASSERT(i->array_part); + return i->t->array[i->index]; +} -/** upb/json_decode.c ************************************************************/ +void upb_inttable_begin(upb_inttable_iter* i, const upb_inttable* t) { + i->t = t; + i->index = -1; + i->array_part = true; + upb_inttable_next(i); +} -#include -#include -#include -#include -#include -#include -#include -#include +void upb_inttable_next(upb_inttable_iter* iter) { + const upb_inttable* t = iter->t; + if (iter->array_part) { + while (++iter->index < t->array_size) { + if (upb_arrhas(int_arrent(iter))) { + return; + } + } + iter->array_part = false; + iter->index = begin(&t->t); + } else { + iter->index = next(&t->t, iter->index); + } +} +bool upb_inttable_next2(const upb_inttable* t, uintptr_t* key, upb_value* val, + intptr_t* iter) { + intptr_t i = *iter; + if (i < t->array_size) { + while (++i < t->array_size) { + upb_tabval ent = t->array[i]; + if (upb_arrhas(ent)) { + *key = i; + *val = _upb_value_val(ent.val); + *iter = i; + return true; + } + } + } -/* Special header, must be included last. */ + size_t tab_idx = next(&t->t, i == -1 ? -1 : i - t->array_size); + if (tab_idx < upb_table_size(&t->t)) { + upb_tabent* ent = &t->t.entries[tab_idx]; + *key = ent->key; + *val = _upb_value_val(ent->val.val); + *iter = tab_idx + t->array_size; + return true; + } -typedef struct { - const char *ptr, *end; - upb_Arena* arena; /* TODO: should we have a tmp arena for tmp data? */ - const upb_DefPool* symtab; - int depth; - upb_Status* status; - jmp_buf err; - int line; - const char* line_begin; - bool is_first; - int options; - const upb_FieldDef* debug_field; -} jsondec; + return false; +} -enum { JD_OBJECT, JD_ARRAY, JD_STRING, JD_NUMBER, JD_TRUE, JD_FALSE, JD_NULL }; +void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter) { + intptr_t i = *iter; + if (i < t->array_size) { + t->array_count--; + mutable_array(t)[i].val = -1; + } else { + upb_tabent* ent = &t->t.entries[i - t->array_size]; + upb_tabent* prev = NULL; -/* Forward declarations of mutually-recursive functions. */ -static void jsondec_wellknown(jsondec* d, upb_Message* msg, - const upb_MessageDef* m); -static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f); -static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, - const upb_MessageDef* m); -static void jsondec_object(jsondec* d, upb_Message* msg, - const upb_MessageDef* m); + // Linear search, not great. + upb_tabent* end = &t->t.entries[upb_table_size(&t->t)]; + for (upb_tabent* e = t->t.entries; e != end; e++) { + if (e->next == ent) { + prev = e; + break; + } + } -static bool jsondec_streql(upb_StringView str, const char* lit) { - return str.size == strlen(lit) && memcmp(str.data, lit, str.size) == 0; -} + if (prev) { + prev->next = ent->next; + } -static bool jsondec_isnullvalue(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Enum && - strcmp(upb_EnumDef_FullName(upb_FieldDef_EnumSubDef(f)), - "google.protobuf.NullValue") == 0; + t->t.count--; + ent->key = 0; + ent->next = NULL; + } } -static bool jsondec_isvalue(const upb_FieldDef* f) { - return (upb_FieldDef_CType(f) == kUpb_CType_Message && - upb_MessageDef_WellKnownType(upb_FieldDef_MessageSubDef(f)) == - kUpb_WellKnown_Value) || - jsondec_isnullvalue(f); -} +bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key, + upb_value* val, intptr_t* iter) { + size_t tab_idx = next(&t->t, *iter); + if (tab_idx < upb_table_size(&t->t)) { + upb_tabent* ent = &t->t.entries[tab_idx]; + uint32_t len; + key->data = upb_tabstr(ent->key, &len); + key->size = len; + *val = _upb_value_val(ent->val.val); + *iter = tab_idx; + return true; + } -UPB_NORETURN static void jsondec_err(jsondec* d, const char* msg) { - upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: %s", d->line, - (int)(d->ptr - d->line_begin), msg); - UPB_LONGJMP(d->err, 1); + return false; } -UPB_PRINTF(2, 3) -UPB_NORETURN static void jsondec_errf(jsondec* d, const char* fmt, ...) { - va_list argp; - upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: ", d->line, - (int)(d->ptr - d->line_begin)); - va_start(argp, fmt); - upb_Status_VAppendErrorFormat(d->status, fmt, argp); - va_end(argp); - UPB_LONGJMP(d->err, 1); -} +void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter) { + intptr_t i = *iter; + upb_tabent* ent = &t->t.entries[i]; + upb_tabent* prev = NULL; -static void jsondec_skipws(jsondec* d) { - while (d->ptr != d->end) { - switch (*d->ptr) { - case '\n': - d->line++; - d->line_begin = d->ptr; - /* Fallthrough. */ - case '\r': - case '\t': - case ' ': - d->ptr++; - break; - default: - return; + // Linear search, not great. + upb_tabent* end = &t->t.entries[upb_table_size(&t->t)]; + for (upb_tabent* e = t->t.entries; e != end; e++) { + if (e->next == ent) { + prev = e; + break; } } - jsondec_err(d, "Unexpected EOF"); -} -static bool jsondec_tryparsech(jsondec* d, char ch) { - if (d->ptr == d->end || *d->ptr != ch) return false; - d->ptr++; - return true; + if (prev) { + prev->next = ent->next; + } + + t->t.count--; + ent->key = 0; + ent->next = NULL; } -static void jsondec_parselit(jsondec* d, const char* lit) { - size_t avail = d->end - d->ptr; - size_t len = strlen(lit); - if (avail < len || memcmp(d->ptr, lit, len) != 0) { - jsondec_errf(d, "Expected: '%s'", lit); +bool upb_inttable_done(const upb_inttable_iter* i) { + if (!i->t) return true; + if (i->array_part) { + return i->index >= i->t->array_size || !upb_arrhas(int_arrent(i)); + } else { + return i->index >= upb_table_size(&i->t->t) || + upb_tabent_isempty(int_tabent(i)); } - d->ptr += len; } -static void jsondec_wsch(jsondec* d, char ch) { - jsondec_skipws(d); - if (!jsondec_tryparsech(d, ch)) { - jsondec_errf(d, "Expected: '%c'", ch); - } +uintptr_t upb_inttable_iter_key(const upb_inttable_iter* i) { + UPB_ASSERT(!upb_inttable_done(i)); + return i->array_part ? i->index : int_tabent(i)->key; } -static void jsondec_true(jsondec* d) { jsondec_parselit(d, "true"); } -static void jsondec_false(jsondec* d) { jsondec_parselit(d, "false"); } -static void jsondec_null(jsondec* d) { jsondec_parselit(d, "null"); } +upb_value upb_inttable_iter_value(const upb_inttable_iter* i) { + UPB_ASSERT(!upb_inttable_done(i)); + return _upb_value_val(i->array_part ? i->t->array[i->index].val + : int_tabent(i)->val.val); +} -static void jsondec_entrysep(jsondec* d) { - jsondec_skipws(d); - jsondec_parselit(d, ":"); +void upb_inttable_iter_setdone(upb_inttable_iter* i) { + i->t = NULL; + i->index = SIZE_MAX; + i->array_part = false; } -static int jsondec_rawpeek(jsondec* d) { - switch (*d->ptr) { - case '{': - return JD_OBJECT; - case '[': - return JD_ARRAY; - case '"': - return JD_STRING; - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return JD_NUMBER; - case 't': - return JD_TRUE; - case 'f': - return JD_FALSE; - case 'n': - return JD_NULL; - default: - jsondec_errf(d, "Unexpected character: '%c'", *d->ptr); - } +bool upb_inttable_iter_isequal(const upb_inttable_iter* i1, + const upb_inttable_iter* i2) { + if (upb_inttable_done(i1) && upb_inttable_done(i2)) return true; + return i1->t == i2->t && i1->index == i2->index && + i1->array_part == i2->array_part; } -/* JSON object/array **********************************************************/ -/* These are used like so: - * - * jsondec_objstart(d); - * while (jsondec_objnext(d)) { - * ... - * } - * jsondec_objend(d) */ +// Must be last. -static int jsondec_peek(jsondec* d) { - jsondec_skipws(d); - return jsondec_rawpeek(d); +int upb_Unicode_ToUTF8(uint32_t cp, char* out) { + if (cp <= 0x7f) { + out[0] = cp; + return 1; + } + if (cp <= 0x07ff) { + out[0] = (cp >> 6) | 0xc0; + out[1] = (cp & 0x3f) | 0x80; + return 2; + } + if (cp <= 0xffff) { + out[0] = (cp >> 12) | 0xe0; + out[1] = ((cp >> 6) & 0x3f) | 0x80; + out[2] = (cp & 0x3f) | 0x80; + return 3; + } + if (cp <= 0x10ffff) { + out[0] = (cp >> 18) | 0xf0; + out[1] = ((cp >> 12) & 0x3f) | 0x80; + out[2] = ((cp >> 6) & 0x3f) | 0x80; + out[3] = (cp & 0x3f) | 0x80; + return 4; + } + return 0; } -static void jsondec_push(jsondec* d) { - if (--d->depth < 0) { - jsondec_err(d, "Recursion limit exceeded"); + +#include + +// Must be last. + +static void* upb_global_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize, + size_t size) { + UPB_UNUSED(alloc); + UPB_UNUSED(oldsize); + if (size == 0) { + free(ptr); + return NULL; + } else { + return realloc(ptr, size); } - d->is_first = true; } -static bool jsondec_seqnext(jsondec* d, char end_ch) { - bool is_first = d->is_first; - d->is_first = false; - jsondec_skipws(d); - if (*d->ptr == end_ch) return false; - if (!is_first) jsondec_parselit(d, ","); - return true; +upb_alloc upb_alloc_global = {&upb_global_allocfunc}; + + +// Must be last. + +static uint32_t* upb_cleanup_pointer(uintptr_t cleanup_metadata) { + return (uint32_t*)(cleanup_metadata & ~0x1); } -static void jsondec_arrstart(jsondec* d) { - jsondec_push(d); - jsondec_wsch(d, '['); +static bool upb_cleanup_has_initial_block(uintptr_t cleanup_metadata) { + return cleanup_metadata & 0x1; } -static void jsondec_arrend(jsondec* d) { - d->depth++; - jsondec_wsch(d, ']'); +static uintptr_t upb_cleanup_metadata(uint32_t* cleanup, + bool has_initial_block) { + return (uintptr_t)cleanup | has_initial_block; } -static bool jsondec_arrnext(jsondec* d) { return jsondec_seqnext(d, ']'); } +struct mem_block { + struct mem_block* next; + uint32_t size; + uint32_t cleanups; + /* Data follows. */ +}; -static void jsondec_objstart(jsondec* d) { - jsondec_push(d); - jsondec_wsch(d, '{'); -} +typedef struct cleanup_ent { + upb_CleanupFunc* cleanup; + void* ud; +} cleanup_ent; -static void jsondec_objend(jsondec* d) { - d->depth++; - jsondec_wsch(d, '}'); -} +static const size_t memblock_reserve = + UPB_ALIGN_UP(sizeof(mem_block), UPB_MALLOC_ALIGN); -static bool jsondec_objnext(jsondec* d) { - if (!jsondec_seqnext(d, '}')) return false; - if (jsondec_peek(d) != JD_STRING) { - jsondec_err(d, "Object must start with string"); +static upb_Arena* arena_findroot(upb_Arena* a) { + /* Path splitting keeps time complexity down, see: + * https://en.wikipedia.org/wiki/Disjoint-set_data_structure */ + while (a->parent != a) { + upb_Arena* next = a->parent; + a->parent = next->parent; + a = next; } - return true; + return a; } -/* JSON number ****************************************************************/ +size_t upb_Arena_SpaceAllocated(upb_Arena* arena) { + arena = arena_findroot(arena); + size_t memsize = 0; -static bool jsondec_tryskipdigits(jsondec* d) { - const char* start = d->ptr; + mem_block* block = arena->freelist; - while (d->ptr < d->end) { - if (*d->ptr < '0' || *d->ptr > '9') { - break; - } - d->ptr++; + while (block) { + memsize += sizeof(mem_block) + block->size; + block = block->next; } - return d->ptr != start; + return memsize; } -static void jsondec_skipdigits(jsondec* d) { - if (!jsondec_tryskipdigits(d)) { - jsondec_err(d, "Expected one or more digits"); - } +uint32_t upb_Arena_DebugRefCount(upb_Arena* arena) { + return arena_findroot(arena)->refcount; } -static double jsondec_number(jsondec* d) { - const char* start = d->ptr; - - assert(jsondec_rawpeek(d) == JD_NUMBER); - - /* Skip over the syntax of a number, as specified by JSON. */ - if (*d->ptr == '-') d->ptr++; +static void upb_Arena_addblock(upb_Arena* a, upb_Arena* root, void* ptr, + size_t size) { + mem_block* block = ptr; - if (jsondec_tryparsech(d, '0')) { - if (jsondec_tryskipdigits(d)) { - jsondec_err(d, "number cannot have leading zero"); - } - } else { - jsondec_skipdigits(d); - } + /* The block is for arena |a|, but should appear in the freelist of |root|. */ + block->next = root->freelist; + block->size = (uint32_t)size; + block->cleanups = 0; + root->freelist = block; + a->last_size = block->size; + if (!root->freelist_tail) root->freelist_tail = block; - if (d->ptr == d->end) goto parse; - if (jsondec_tryparsech(d, '.')) { - jsondec_skipdigits(d); - } - if (d->ptr == d->end) goto parse; + a->head.ptr = UPB_PTR_AT(block, memblock_reserve, char); + a->head.end = UPB_PTR_AT(block, size, char); + a->cleanup_metadata = upb_cleanup_metadata( + &block->cleanups, upb_cleanup_has_initial_block(a->cleanup_metadata)); - if (*d->ptr == 'e' || *d->ptr == 'E') { - d->ptr++; - if (d->ptr == d->end) { - jsondec_err(d, "Unexpected EOF in number"); - } - if (*d->ptr == '+' || *d->ptr == '-') { - d->ptr++; - } - jsondec_skipdigits(d); - } + UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr); +} -parse: - /* Having verified the syntax of a JSON number, use strtod() to parse - * (strtod() accepts a superset of JSON syntax). */ - errno = 0; - { - char* end; - double val = strtod(start, &end); - assert(end == d->ptr); +static bool upb_Arena_Allocblock(upb_Arena* a, size_t size) { + upb_Arena* root = arena_findroot(a); + size_t block_size = UPB_MAX(size, a->last_size * 2) + memblock_reserve; + mem_block* block = upb_malloc(root->block_alloc, block_size); - /* Currently the min/max-val conformance tests fail if we check this. Does - * this mean the conformance tests are wrong or strtod() is wrong, or - * something else? Investigate further. */ - /* - if (errno == ERANGE) { - jsondec_err(d, "Number out of range"); - } - */ + if (!block) return false; + upb_Arena_addblock(a, root, block, block_size); + return true; +} - if (val > DBL_MAX || val < -DBL_MAX) { - jsondec_err(d, "Number out of range"); - } +void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size) { + if (!upb_Arena_Allocblock(a, size)) return NULL; /* Out of memory. */ + UPB_ASSERT(_upb_ArenaHas(a) >= size); + return upb_Arena_Malloc(a, size); +} - return val; - } +static void* upb_Arena_doalloc(upb_alloc* alloc, void* ptr, size_t oldsize, + size_t size) { + upb_Arena* a = (upb_Arena*)alloc; /* upb_alloc is initial member. */ + return upb_Arena_Realloc(a, ptr, oldsize, size); } -/* JSON string ****************************************************************/ +/* Public Arena API ***********************************************************/ -static char jsondec_escape(jsondec* d) { - switch (*d->ptr++) { - case '"': - return '\"'; - case '\\': - return '\\'; - case '/': - return '/'; - case 'b': - return '\b'; - case 'f': - return '\f'; - case 'n': - return '\n'; - case 'r': - return '\r'; - case 't': - return '\t'; - default: - jsondec_err(d, "Invalid escape char"); +static upb_Arena* arena_initslow(void* mem, size_t n, upb_alloc* alloc) { + const size_t first_block_overhead = sizeof(upb_Arena) + memblock_reserve; + upb_Arena* a; + + /* We need to malloc the initial block. */ + n = first_block_overhead + 256; + if (!alloc || !(mem = upb_malloc(alloc, n))) { + return NULL; } -} -static uint32_t jsondec_codepoint(jsondec* d) { - uint32_t cp = 0; - const char* end; + a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); + n -= sizeof(*a); - if (d->end - d->ptr < 4) { - jsondec_err(d, "EOF inside string"); - } + a->head.alloc.func = &upb_Arena_doalloc; + a->block_alloc = alloc; + a->parent = a; + a->refcount = 1; + a->freelist = NULL; + a->freelist_tail = NULL; + a->cleanup_metadata = upb_cleanup_metadata(NULL, false); - end = d->ptr + 4; - while (d->ptr < end) { - char ch = *d->ptr++; - if (ch >= '0' && ch <= '9') { - ch -= '0'; - } else if (ch >= 'a' && ch <= 'f') { - ch = ch - 'a' + 10; - } else if (ch >= 'A' && ch <= 'F') { - ch = ch - 'A' + 10; - } else { - jsondec_err(d, "Invalid hex digit"); - } - cp = (cp << 4) | ch; - } + upb_Arena_addblock(a, a, mem, n); - return cp; + return a; } -/* Parses a \uXXXX unicode escape (possibly a surrogate pair). */ -static size_t jsondec_unicode(jsondec* d, char* out) { - uint32_t cp = jsondec_codepoint(d); - if (cp >= 0xd800 && cp <= 0xdbff) { - /* Surrogate pair: two 16-bit codepoints become a 32-bit codepoint. */ - uint32_t high = cp; - uint32_t low; - jsondec_parselit(d, "\\u"); - low = jsondec_codepoint(d); - if (low < 0xdc00 || low > 0xdfff) { - jsondec_err(d, "Invalid low surrogate"); - } - cp = (high & 0x3ff) << 10; - cp |= (low & 0x3ff); - cp += 0x10000; - } else if (cp >= 0xdc00 && cp <= 0xdfff) { - jsondec_err(d, "Unpaired low surrogate"); - } +upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) { + upb_Arena* a; - /* Write to UTF-8 */ - if (cp <= 0x7f) { - out[0] = cp; - return 1; - } else if (cp <= 0x07FF) { - out[0] = ((cp >> 6) & 0x1F) | 0xC0; - out[1] = ((cp >> 0) & 0x3F) | 0x80; - return 2; - } else if (cp <= 0xFFFF) { - out[0] = ((cp >> 12) & 0x0F) | 0xE0; - out[1] = ((cp >> 6) & 0x3F) | 0x80; - out[2] = ((cp >> 0) & 0x3F) | 0x80; - return 3; - } else if (cp < 0x10FFFF) { - out[0] = ((cp >> 18) & 0x07) | 0xF0; - out[1] = ((cp >> 12) & 0x3f) | 0x80; - out[2] = ((cp >> 6) & 0x3f) | 0x80; - out[3] = ((cp >> 0) & 0x3f) | 0x80; - return 4; - } else { - jsondec_err(d, "Invalid codepoint"); + if (n) { + /* Align initial pointer up so that we return properly-aligned pointers. */ + void* aligned = (void*)UPB_ALIGN_UP((uintptr_t)mem, UPB_MALLOC_ALIGN); + size_t delta = (uintptr_t)aligned - (uintptr_t)mem; + n = delta <= n ? n - delta : 0; + mem = aligned; } -} -static void jsondec_resize(jsondec* d, char** buf, char** end, char** buf_end) { - size_t oldsize = *buf_end - *buf; - size_t len = *end - *buf; - size_t size = UPB_MAX(8, 2 * oldsize); + /* Round block size down to alignof(*a) since we will allocate the arena + * itself at the end. */ + n = UPB_ALIGN_DOWN(n, UPB_ALIGN_OF(upb_Arena)); - *buf = upb_Arena_Realloc(d->arena, *buf, len, size); - if (!*buf) jsondec_err(d, "Out of memory"); + if (UPB_UNLIKELY(n < sizeof(upb_Arena))) { + return arena_initslow(mem, n, alloc); + } - *end = *buf + len; - *buf_end = *buf + size; -} + a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); -static upb_StringView jsondec_string(jsondec* d) { - char* buf = NULL; - char* end = NULL; - char* buf_end = NULL; + a->head.alloc.func = &upb_Arena_doalloc; + a->block_alloc = alloc; + a->parent = a; + a->refcount = 1; + a->last_size = UPB_MAX(128, n); + a->head.ptr = mem; + a->head.end = UPB_PTR_AT(mem, n - sizeof(*a), char); + a->freelist = NULL; + a->freelist_tail = NULL; + a->cleanup_metadata = upb_cleanup_metadata(NULL, true); - jsondec_skipws(d); + return a; +} - if (*d->ptr++ != '"') { - jsondec_err(d, "Expected string"); - } +static void arena_dofree(upb_Arena* a) { + mem_block* block = a->freelist; + UPB_ASSERT(a->parent == a); + UPB_ASSERT(a->refcount == 0); - while (d->ptr < d->end) { - char ch = *d->ptr++; + while (block) { + /* Load first since we are deleting block. */ + mem_block* next = block->next; - if (end == buf_end) { - jsondec_resize(d, &buf, &end, &buf_end); - } + if (block->cleanups > 0) { + cleanup_ent* end = UPB_PTR_AT(block, block->size, void); + cleanup_ent* ptr = end - block->cleanups; - switch (ch) { - case '"': { - upb_StringView ret; - ret.data = buf; - ret.size = end - buf; - *end = '\0'; /* Needed for possible strtod(). */ - return ret; + for (; ptr < end; ptr++) { + ptr->cleanup(ptr->ud); } - case '\\': - if (d->ptr == d->end) goto eof; - if (*d->ptr == 'u') { - d->ptr++; - if (buf_end - end < 4) { - /* Allow space for maximum-sized code point (4 bytes). */ - jsondec_resize(d, &buf, &end, &buf_end); - } - end += jsondec_unicode(d, end); - } else { - *end++ = jsondec_escape(d); - } - break; - default: - if ((unsigned char)*d->ptr < 0x20) { - jsondec_err(d, "Invalid char in JSON string"); - } - *end++ = ch; - break; } + + upb_free(a->block_alloc, block); + block = next; } +} -eof: - jsondec_err(d, "EOF inside string"); +void upb_Arena_Free(upb_Arena* a) { + a = arena_findroot(a); + if (--a->refcount == 0) arena_dofree(a); } -static void jsondec_skipval(jsondec* d) { - switch (jsondec_peek(d)) { - case JD_OBJECT: - jsondec_objstart(d); - while (jsondec_objnext(d)) { - jsondec_string(d); - jsondec_entrysep(d); - jsondec_skipval(d); - } - jsondec_objend(d); - break; - case JD_ARRAY: - jsondec_arrstart(d); - while (jsondec_arrnext(d)) { - jsondec_skipval(d); - } - jsondec_arrend(d); - break; - case JD_TRUE: - jsondec_true(d); - break; - case JD_FALSE: - jsondec_false(d); - break; - case JD_NULL: - jsondec_null(d); - break; - case JD_STRING: - jsondec_string(d); - break; - case JD_NUMBER: - jsondec_number(d); - break; +bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func) { + cleanup_ent* ent; + uint32_t* cleanups = upb_cleanup_pointer(a->cleanup_metadata); + + if (!cleanups || _upb_ArenaHas(a) < sizeof(cleanup_ent)) { + if (!upb_Arena_Allocblock(a, 128)) return false; /* Out of memory. */ + UPB_ASSERT(_upb_ArenaHas(a) >= sizeof(cleanup_ent)); + cleanups = upb_cleanup_pointer(a->cleanup_metadata); } -} -/* Base64 decoding for bytes fields. ******************************************/ + a->head.end -= sizeof(cleanup_ent); + ent = (cleanup_ent*)a->head.end; + (*cleanups)++; + UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent)); -static unsigned int jsondec_base64_tablelookup(const char ch) { - /* Table includes the normal base64 chars plus the URL-safe variant. */ - const signed char table[256] = { - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, 62 /*+*/, -1, 62 /*-*/, -1, 63 /*/ */, 52 /*0*/, - 53 /*1*/, 54 /*2*/, 55 /*3*/, 56 /*4*/, 57 /*5*/, 58 /*6*/, 59 /*7*/, - 60 /*8*/, 61 /*9*/, -1, -1, -1, -1, -1, - -1, -1, 0 /*A*/, 1 /*B*/, 2 /*C*/, 3 /*D*/, 4 /*E*/, - 5 /*F*/, 6 /*G*/, 07 /*H*/, 8 /*I*/, 9 /*J*/, 10 /*K*/, 11 /*L*/, - 12 /*M*/, 13 /*N*/, 14 /*O*/, 15 /*P*/, 16 /*Q*/, 17 /*R*/, 18 /*S*/, - 19 /*T*/, 20 /*U*/, 21 /*V*/, 22 /*W*/, 23 /*X*/, 24 /*Y*/, 25 /*Z*/, - -1, -1, -1, -1, 63 /*_*/, -1, 26 /*a*/, - 27 /*b*/, 28 /*c*/, 29 /*d*/, 30 /*e*/, 31 /*f*/, 32 /*g*/, 33 /*h*/, - 34 /*i*/, 35 /*j*/, 36 /*k*/, 37 /*l*/, 38 /*m*/, 39 /*n*/, 40 /*o*/, - 41 /*p*/, 42 /*q*/, 43 /*r*/, 44 /*s*/, 45 /*t*/, 46 /*u*/, 47 /*v*/, - 48 /*w*/, 49 /*x*/, 50 /*y*/, 51 /*z*/, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1}; + ent->cleanup = func; + ent->ud = ud; - /* Sign-extend return value so high bit will be set on any unexpected char. */ - return table[(unsigned)ch]; + return true; } -static char* jsondec_partialbase64(jsondec* d, const char* ptr, const char* end, - char* out) { - int32_t val = -1; +bool upb_Arena_Fuse(upb_Arena* a1, upb_Arena* a2) { + upb_Arena* r1 = arena_findroot(a1); + upb_Arena* r2 = arena_findroot(a2); - switch (end - ptr) { - case 2: - val = jsondec_base64_tablelookup(ptr[0]) << 18 | - jsondec_base64_tablelookup(ptr[1]) << 12; - out[0] = val >> 16; - out += 1; - break; - case 3: - val = jsondec_base64_tablelookup(ptr[0]) << 18 | - jsondec_base64_tablelookup(ptr[1]) << 12 | - jsondec_base64_tablelookup(ptr[2]) << 6; - out[0] = val >> 16; - out[1] = (val >> 8) & 0xff; - out += 2; - break; - } + if (r1 == r2) return true; /* Already fused. */ - if (val < 0) { - jsondec_err(d, "Corrupt base64"); + /* Do not fuse initial blocks since we cannot lifetime extend them. */ + if (upb_cleanup_has_initial_block(r1->cleanup_metadata)) return false; + if (upb_cleanup_has_initial_block(r2->cleanup_metadata)) return false; + + /* Only allow fuse with a common allocator */ + if (r1->block_alloc != r2->block_alloc) return false; + + /* We want to join the smaller tree to the larger tree. + * So swap first if they are backwards. */ + if (r1->refcount < r2->refcount) { + upb_Arena* tmp = r1; + r1 = r2; + r2 = tmp; } - return out; + /* r1 takes over r2's freelist and refcount. */ + r1->refcount += r2->refcount; + if (r2->freelist_tail) { + UPB_ASSERT(r2->freelist_tail->next == NULL); + r2->freelist_tail->next = r1->freelist; + r1->freelist = r2->freelist; + } + r2->parent = r1; + return true; } -static size_t jsondec_base64(jsondec* d, upb_StringView str) { - /* We decode in place. This is safe because this is a new buffer (not - * aliasing the input) and because base64 decoding shrinks 4 bytes into 3. */ - char* out = (char*)str.data; - const char* ptr = str.data; - const char* end = ptr + str.size; - const char* end4 = ptr + (str.size & -4); /* Round down to multiple of 4. */ - for (; ptr < end4; ptr += 4, out += 3) { - int val = jsondec_base64_tablelookup(ptr[0]) << 18 | - jsondec_base64_tablelookup(ptr[1]) << 12 | - jsondec_base64_tablelookup(ptr[2]) << 6 | - jsondec_base64_tablelookup(ptr[3]) << 0; +#include - if (val < 0) { - /* Junk chars or padding. Remove trailing padding, if any. */ - if (end - ptr == 4 && ptr[3] == '=') { - if (ptr[2] == '=') { - end -= 2; - } else { - end -= 1; - } - } - break; - } +// Must be last. + +static const char _upb_CTypeo_sizelg2[12] = { + 0, + 0, /* kUpb_CType_Bool */ + 2, /* kUpb_CType_Float */ + 2, /* kUpb_CType_Int32 */ + 2, /* kUpb_CType_UInt32 */ + 2, /* kUpb_CType_Enum */ + UPB_SIZE(2, 3), /* kUpb_CType_Message */ + 3, /* kUpb_CType_Double */ + 3, /* kUpb_CType_Int64 */ + 3, /* kUpb_CType_UInt64 */ + UPB_SIZE(3, 4), /* kUpb_CType_String */ + UPB_SIZE(3, 4), /* kUpb_CType_Bytes */ +}; + +upb_Array* upb_Array_New(upb_Arena* a, upb_CType type) { + return _upb_Array_New(a, 4, _upb_CTypeo_sizelg2[type]); +} + +size_t upb_Array_Size(const upb_Array* arr) { return arr->size; } + +upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i) { + upb_MessageValue ret; + const char* data = _upb_array_constptr(arr); + int lg2 = arr->data & 7; + UPB_ASSERT(i < arr->size); + memcpy(&ret, data + (i << lg2), 1 << lg2); + return ret; +} - out[0] = val >> 16; - out[1] = (val >> 8) & 0xff; - out[2] = val & 0xff; - } +void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) { + char* data = _upb_array_ptr(arr); + int lg2 = arr->data & 7; + UPB_ASSERT(i < arr->size); + memcpy(data + (i << lg2), &val, 1 << lg2); +} - if (ptr < end) { - /* Process remaining chars. We do not require padding. */ - out = jsondec_partialbase64(d, ptr, end, out); +bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) { + if (!upb_Array_Resize(arr, arr->size + 1, arena)) { + return false; } - - return out - str.data; + upb_Array_Set(arr, arr->size - 1, val); + return true; } -/* Low-level integer parsing **************************************************/ - -/* We use these hand-written routines instead of strto[u]l() because the "long - * long" variants aren't in c89. Also our version allows setting a ptr limit. */ +void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx, + size_t count) { + char* data = _upb_array_ptr(arr); + int lg2 = arr->data & 7; + memmove(&data[dst_idx << lg2], &data[src_idx << lg2], count << lg2); +} -static const char* jsondec_buftouint64(jsondec* d, const char* ptr, - const char* end, uint64_t* val) { - uint64_t u64 = 0; - while (ptr < end) { - unsigned ch = *ptr - '0'; - if (ch >= 10) break; - if (u64 > UINT64_MAX / 10 || u64 * 10 > UINT64_MAX - ch) { - jsondec_err(d, "Integer overflow"); - } - u64 *= 10; - u64 += ch; - ptr++; +bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count, + upb_Arena* arena) { + UPB_ASSERT(i <= arr->size); + UPB_ASSERT(count + arr->size >= count); + size_t oldsize = arr->size; + if (!upb_Array_Resize(arr, arr->size + count, arena)) { + return false; } + upb_Array_Move(arr, i + count, i, oldsize - i); + return true; +} - *val = u64; - return ptr; +/* + * i end arr->size + * |------------|XXXXXXXX|--------| + */ +void upb_Array_Delete(upb_Array* arr, size_t i, size_t count) { + size_t end = i + count; + UPB_ASSERT(i <= end); + UPB_ASSERT(end <= arr->size); + upb_Array_Move(arr, i, end, arr->size - end); + arr->size -= count; } -static const char* jsondec_buftoint64(jsondec* d, const char* ptr, - const char* end, int64_t* val) { - bool neg = false; - uint64_t u64; +bool upb_Array_Resize(upb_Array* arr, size_t size, upb_Arena* arena) { + return _upb_Array_Resize(arr, size, arena); +} - if (ptr != end && *ptr == '-') { - ptr++; - neg = true; - } - ptr = jsondec_buftouint64(d, ptr, end, &u64); - if (u64 > (uint64_t)INT64_MAX + neg) { - jsondec_err(d, "Integer overflow"); - } +#include - *val = neg ? -u64 : u64; - return ptr; -} -static uint64_t jsondec_strtouint64(jsondec* d, upb_StringView str) { - const char* end = str.data + str.size; - uint64_t ret; - if (jsondec_buftouint64(d, str.data, end, &ret) != end) { - jsondec_err(d, "Non-number characters in quoted integer"); - } - return ret; -} +// Must be last. -static int64_t jsondec_strtoint64(jsondec* d, upb_StringView str) { - const char* end = str.data + str.size; - int64_t ret; - if (jsondec_buftoint64(d, str.data, end, &ret) != end) { - jsondec_err(d, "Non-number characters in quoted integer"); - } - return ret; -} +// A few fake field types for our tables. +enum { + kUpb_FakeFieldType_FieldNotFound = 0, + kUpb_FakeFieldType_MessageSetItem = 19, +}; -/* Primitive value types ******************************************************/ +// DecodeOp: an action to be performed for a wire-type/field-type combination. +enum { + // Special ops: we don't write data to regular fields for these. + kUpb_DecodeOp_UnknownField = -1, + kUpb_DecodeOp_MessageSetItem = -2, + + // Scalar-only ops. + kUpb_DecodeOp_Scalar1Byte = 0, + kUpb_DecodeOp_Scalar4Byte = 2, + kUpb_DecodeOp_Scalar8Byte = 3, + kUpb_DecodeOp_Enum = 1, + + // Scalar/repeated ops. + kUpb_DecodeOp_String = 4, + kUpb_DecodeOp_Bytes = 5, + kUpb_DecodeOp_SubMessage = 6, + + // Repeated-only ops (also see macros below). + kUpb_DecodeOp_PackedEnum = 13, +}; -/* Parse INT32 or INT64 value. */ -static upb_MessageValue jsondec_int(jsondec* d, const upb_FieldDef* f) { - upb_MessageValue val; +// For packed fields it is helpful to be able to recover the lg2 of the data +// size from the op. +#define OP_FIXPCK_LG2(n) (n + 5) /* n in [2, 3] => op in [7, 8] */ +#define OP_VARPCK_LG2(n) (n + 9) /* n in [0, 2, 3] => op in [9, 11, 12] */ - switch (jsondec_peek(d)) { - case JD_NUMBER: { - double dbl = jsondec_number(d); - if (dbl > 9223372036854774784.0 || dbl < -9223372036854775808.0) { - jsondec_err(d, "JSON number is out of range."); - } - val.int64_val = dbl; /* must be guarded, overflow here is UB */ - if (val.int64_val != dbl) { - jsondec_errf(d, "JSON number was not integral (%f != %" PRId64 ")", dbl, - val.int64_val); - } - break; - } - case JD_STRING: { - upb_StringView str = jsondec_string(d); - val.int64_val = jsondec_strtoint64(d, str); - break; - } - default: - jsondec_err(d, "Expected number or string"); - } +typedef union { + bool bool_val; + uint32_t uint32_val; + uint64_t uint64_val; + uint32_t size; +} wireval; - if (upb_FieldDef_CType(f) == kUpb_CType_Int32 || - upb_FieldDef_CType(f) == kUpb_CType_Enum) { - if (val.int64_val > INT32_MAX || val.int64_val < INT32_MIN) { - jsondec_err(d, "Integer out of range."); - } - val.int32_val = (int32_t)val.int64_val; - } +static const char* _upb_Decoder_DecodeMessage(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable* layout); - return val; +UPB_NORETURN static void* _upb_Decoder_ErrorJmp(upb_Decoder* d, + upb_DecodeStatus status) { + assert(status != kUpb_DecodeStatus_Ok); + UPB_LONGJMP(d->err, status); } -/* Parse UINT32 or UINT64 value. */ -static upb_MessageValue jsondec_uint(jsondec* d, const upb_FieldDef* f) { - upb_MessageValue val = {0}; +const char* _upb_FastDecoder_ErrorJmp(upb_Decoder* d, int status) { + assert(status != kUpb_DecodeStatus_Ok); + UPB_LONGJMP(d->err, status); + return NULL; +} +static void _upb_Decoder_VerifyUtf8(upb_Decoder* d, const char* buf, int len) { + if (!_upb_Decoder_VerifyUtf8Inline(buf, len)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_BadUtf8); + } +} - switch (jsondec_peek(d)) { - case JD_NUMBER: { - double dbl = jsondec_number(d); - if (dbl > 18446744073709549568.0 || dbl < 0) { - jsondec_err(d, "JSON number is out of range."); - } - val.uint64_val = dbl; /* must be guarded, overflow here is UB */ - if (val.uint64_val != dbl) { - jsondec_errf(d, "JSON number was not integral (%f != %" PRIu64 ")", dbl, - val.uint64_val); - } - break; - } - case JD_STRING: { - upb_StringView str = jsondec_string(d); - val.uint64_val = jsondec_strtouint64(d, str); - break; - } - default: - jsondec_err(d, "Expected number or string"); +static bool _upb_Decoder_Reserve(upb_Decoder* d, upb_Array* arr, size_t elem) { + bool need_realloc = arr->capacity - arr->size < elem; + if (need_realloc && !_upb_array_realloc(arr, arr->size + elem, &d->arena)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); } + return need_realloc; +} - if (upb_FieldDef_CType(f) == kUpb_CType_UInt32) { - if (val.uint64_val > UINT32_MAX) { - jsondec_err(d, "Integer out of range."); +typedef struct { + const char* ptr; + uint64_t val; +} _upb_DecodeLongVarintReturn; + +UPB_NOINLINE +static _upb_DecodeLongVarintReturn _upb_Decoder_DecodeLongVarint( + const char* ptr, uint64_t val) { + _upb_DecodeLongVarintReturn ret = {NULL, 0}; + uint64_t byte; + int i; + for (i = 1; i < 10; i++) { + byte = (uint8_t)ptr[i]; + val += (byte - 1) << (i * 7); + if (!(byte & 0x80)) { + ret.ptr = ptr + i + 1; + ret.val = val; + return ret; } - val.uint32_val = (uint32_t)val.uint64_val; } - - return val; + return ret; } -/* Parse DOUBLE or FLOAT value. */ -static upb_MessageValue jsondec_double(jsondec* d, const upb_FieldDef* f) { - upb_StringView str; - upb_MessageValue val = {0}; - - switch (jsondec_peek(d)) { - case JD_NUMBER: - val.double_val = jsondec_number(d); - break; - case JD_STRING: - str = jsondec_string(d); - if (jsondec_streql(str, "NaN")) { - val.double_val = NAN; - } else if (jsondec_streql(str, "Infinity")) { - val.double_val = INFINITY; - } else if (jsondec_streql(str, "-Infinity")) { - val.double_val = -INFINITY; - } else { - val.double_val = strtod(str.data, NULL); - } - break; - default: - jsondec_err(d, "Expected number or string"); +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeVarint(upb_Decoder* d, const char* ptr, + uint64_t* val) { + uint64_t byte = (uint8_t)*ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = byte; + return ptr + 1; + } else { + _upb_DecodeLongVarintReturn res = _upb_Decoder_DecodeLongVarint(ptr, byte); + if (!res.ptr) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + *val = res.val; + return res.ptr; } +} - if (upb_FieldDef_CType(f) == kUpb_CType_Float) { - if (val.double_val != INFINITY && val.double_val != -INFINITY && - (val.double_val > FLT_MAX || val.double_val < -FLT_MAX)) { - jsondec_err(d, "Float out of range"); +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeTag(upb_Decoder* d, const char* ptr, + uint32_t* val) { + uint64_t byte = (uint8_t)*ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = byte; + return ptr + 1; + } else { + const char* start = ptr; + _upb_DecodeLongVarintReturn res = _upb_Decoder_DecodeLongVarint(ptr, byte); + if (!res.ptr || res.ptr - start > 5 || res.val > UINT32_MAX) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); } - val.float_val = val.double_val; + *val = res.val; + return res.ptr; } +} - return val; +UPB_FORCEINLINE +static const char* upb_Decoder_DecodeSize(upb_Decoder* d, const char* ptr, + uint32_t* size) { + uint64_t size64; + ptr = _upb_Decoder_DecodeVarint(d, ptr, &size64); + if (size64 >= INT32_MAX || ptr - d->end + (int)size64 > d->limit) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + } + *size = size64; + return ptr; } -/* Parse STRING or BYTES value. */ -static upb_MessageValue jsondec_strfield(jsondec* d, const upb_FieldDef* f) { - upb_MessageValue val; - val.str_val = jsondec_string(d); - if (upb_FieldDef_CType(f) == kUpb_CType_Bytes) { - val.str_val.size = jsondec_base64(d, val.str_val); +static void _upb_Decoder_MungeInt32(wireval* val) { + if (!_upb_IsLittleEndian()) { + /* The next stage will memcpy(dst, &val, 4) */ + val->uint32_val = val->uint64_val; } - return val; } -static upb_MessageValue jsondec_enum(jsondec* d, const upb_FieldDef* f) { - switch (jsondec_peek(d)) { - case JD_STRING: { - upb_StringView str = jsondec_string(d); - const upb_EnumDef* e = upb_FieldDef_EnumSubDef(f); - const upb_EnumValueDef* ev = - upb_EnumDef_FindValueByNameWithSize(e, str.data, str.size); - upb_MessageValue val; - if (ev) { - val.int32_val = upb_EnumValueDef_Number(ev); - } else { - if (d->options & upb_JsonDecode_IgnoreUnknown) { - val.int32_val = 0; - } else { - jsondec_errf(d, "Unknown enumerator: '" UPB_STRINGVIEW_FORMAT "'", - UPB_STRINGVIEW_ARGS(str)); - } - } - return val; +static void _upb_Decoder_Munge(int type, wireval* val) { + switch (type) { + case kUpb_FieldType_Bool: + val->bool_val = val->uint64_val != 0; + break; + case kUpb_FieldType_SInt32: { + uint32_t n = val->uint64_val; + val->uint32_val = (n >> 1) ^ -(int32_t)(n & 1); + break; } - case JD_NULL: { - if (jsondec_isnullvalue(f)) { - upb_MessageValue val; - jsondec_null(d); - val.int32_val = 0; - return val; - } + case kUpb_FieldType_SInt64: { + uint64_t n = val->uint64_val; + val->uint64_val = (n >> 1) ^ -(int64_t)(n & 1); + break; } - /* Fallthrough. */ - default: - return jsondec_int(d, f); + case kUpb_FieldType_Int32: + case kUpb_FieldType_UInt32: + case kUpb_FieldType_Enum: + _upb_Decoder_MungeInt32(val); + break; } } -static upb_MessageValue jsondec_bool(jsondec* d, const upb_FieldDef* f) { - bool is_map_key = upb_FieldDef_Number(f) == 1 && - upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f)); - upb_MessageValue val; +static upb_Message* _upb_Decoder_NewSubMessage( + upb_Decoder* d, const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field) { + const upb_MiniTable* subl = subs[field->submsg_index].submsg; + upb_Message* msg = _upb_Message_New_inl(subl, &d->arena); + if (!msg) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + return msg; +} - if (is_map_key) { - upb_StringView str = jsondec_string(d); - if (jsondec_streql(str, "true")) { - val.bool_val = true; - } else if (jsondec_streql(str, "false")) { - val.bool_val = false; - } else { - jsondec_err(d, "Invalid boolean map key"); - } +UPB_NOINLINE +const char* _upb_Decoder_IsDoneFallback(upb_Decoder* d, const char* ptr, + int overrun) { + int status; + ptr = _upb_Decoder_IsDoneFallbackInline(d, ptr, overrun, &status); + if (ptr == NULL) _upb_Decoder_ErrorJmp(d, status); + return ptr; +} + +static const char* _upb_Decoder_ReadString(upb_Decoder* d, const char* ptr, + int size, upb_StringView* str) { + if (d->options & kUpb_DecodeOption_AliasString) { + str->data = ptr; } else { - switch (jsondec_peek(d)) { - case JD_TRUE: - val.bool_val = true; - jsondec_true(d); - break; - case JD_FALSE: - val.bool_val = false; - jsondec_false(d); - break; - default: - jsondec_err(d, "Expected true or false"); - } + char* data = upb_Arena_Malloc(&d->arena, size); + if (!data) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + memcpy(data, ptr, size); + str->data = data; } + str->size = size; + return ptr + size; +} - return val; +UPB_FORCEINLINE +static const char* _upb_Decoder_RecurseSubMessage(upb_Decoder* d, + const char* ptr, + upb_Message* submsg, + const upb_MiniTable* subl, + uint32_t expected_end_group) { + if (--d->depth < 0) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_MaxDepthExceeded); + } + ptr = _upb_Decoder_DecodeMessage(d, ptr, submsg, subl); + d->depth++; + if (d->end_group != expected_end_group) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + } + return ptr; } -/* Composite types (array/message/map) ****************************************/ +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeSubMessage( + upb_Decoder* d, const char* ptr, upb_Message* submsg, + const upb_MiniTable_Sub* subs, const upb_MiniTable_Field* field, int size) { + int saved_delta = _upb_Decoder_PushLimit(d, ptr, size); + const upb_MiniTable* subl = subs[field->submsg_index].submsg; + ptr = _upb_Decoder_RecurseSubMessage(d, ptr, submsg, subl, DECODE_NOGROUP); + _upb_Decoder_PopLimit(d, ptr, saved_delta); + return ptr; +} -static void jsondec_array(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { - upb_Array* arr = upb_Message_Mutable(msg, f, d->arena).array; +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeGroup(upb_Decoder* d, const char* ptr, + upb_Message* submsg, + const upb_MiniTable* subl, + uint32_t number) { + if (_upb_Decoder_IsDone(d, &ptr)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + } + ptr = _upb_Decoder_RecurseSubMessage(d, ptr, submsg, subl, number); + d->end_group = DECODE_NOGROUP; + return ptr; +} - jsondec_arrstart(d); - while (jsondec_arrnext(d)) { - upb_MessageValue elem = jsondec_value(d, f); - upb_Array_Append(arr, elem, d->arena); - } - jsondec_arrend(d); +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeUnknownGroup(upb_Decoder* d, + const char* ptr, + uint32_t number) { + return _upb_Decoder_DecodeGroup(d, ptr, NULL, NULL, number); } -static void jsondec_map(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { - upb_Map* map = upb_Message_Mutable(msg, f, d->arena).map; - const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); - const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); - const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeKnownGroup( + upb_Decoder* d, const char* ptr, upb_Message* submsg, + const upb_MiniTable_Sub* subs, const upb_MiniTable_Field* field) { + const upb_MiniTable* subl = subs[field->submsg_index].submsg; + return _upb_Decoder_DecodeGroup(d, ptr, submsg, subl, field->number); +} - jsondec_objstart(d); - while (jsondec_objnext(d)) { - upb_MessageValue key, val; - key = jsondec_value(d, key_f); - jsondec_entrysep(d); - val = jsondec_value(d, val_f); - upb_Map_Set(map, key, val, d->arena); - } - jsondec_objend(d); +static char* upb_Decoder_EncodeVarint32(uint32_t val, char* ptr) { + do { + uint8_t byte = val & 0x7fU; + val >>= 7; + if (val) byte |= 0x80U; + *(ptr++) = byte; + } while (val); + return ptr; } -static void jsondec_tomsg(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { - jsondec_object(d, msg, m); - } else { - jsondec_wellknown(d, msg, m); +static void _upb_Decoder_AddUnknownVarints(upb_Decoder* d, upb_Message* msg, + uint32_t val1, uint32_t val2) { + char buf[20]; + char* end = buf; + end = upb_Decoder_EncodeVarint32(val1, end); + end = upb_Decoder_EncodeVarint32(val2, end); + + if (!_upb_Message_AddUnknown(msg, buf, end - buf, &d->arena)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); } } -static upb_MessageValue jsondec_msg(jsondec* d, const upb_FieldDef* f) { - const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); - upb_Message* msg = upb_Message_New(m, d->arena); - upb_MessageValue val; +UPB_NOINLINE +static bool _upb_Decoder_CheckEnumSlow(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable_Enum* e, + const upb_MiniTable_Field* field, + uint32_t v) { + if (_upb_MiniTable_CheckEnumValueSlow(e, v)) return true; - jsondec_tomsg(d, msg, m); - val.msg_val = msg; - return val; + // Unrecognized enum goes into unknown fields. + // For packed fields the tag could be arbitrarily far in the past, so we + // just re-encode the tag and value here. + uint32_t tag = ((uint32_t)field->number << 3) | kUpb_WireType_Varint; + upb_Message* unknown_msg = + field->mode & kUpb_LabelFlags_IsExtension ? d->unknown_msg : msg; + _upb_Decoder_AddUnknownVarints(d, unknown_msg, tag, v); + return false; } -static void jsondec_field(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - upb_StringView name; - const upb_FieldDef* f; - const upb_FieldDef* preserved; +UPB_FORCEINLINE +static bool _upb_Decoder_CheckEnum(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable_Enum* e, + const upb_MiniTable_Field* field, + wireval* val) { + uint32_t v = val->uint32_val; - name = jsondec_string(d); - jsondec_entrysep(d); + _kUpb_FastEnumCheck_Status status = _upb_MiniTable_CheckEnumValueFast(e, v); + if (UPB_LIKELY(status == _kUpb_FastEnumCheck_ValueIsInEnum)) return true; + return _upb_Decoder_CheckEnumSlow(d, ptr, msg, e, field, v); +} - if (name.size >= 2 && name.data[0] == '[' && - name.data[name.size - 1] == ']') { - f = upb_DefPool_FindExtensionByNameWithSize(d->symtab, name.data + 1, - name.size - 2); - if (f && upb_FieldDef_ContainingType(f) != m) { - jsondec_errf( - d, "Extension %s extends message %s, but was seen in message %s", - upb_FieldDef_FullName(f), - upb_MessageDef_FullName(upb_FieldDef_ContainingType(f)), - upb_MessageDef_FullName(m)); - } - } else { - f = upb_MessageDef_FindByJsonNameWithSize(m, name.data, name.size); - } +UPB_NOINLINE +static const char* _upb_Decoder_DecodeEnumArray( + upb_Decoder* d, const char* ptr, upb_Message* msg, upb_Array* arr, + const upb_MiniTable_Sub* subs, const upb_MiniTable_Field* field, + wireval* val) { + const upb_MiniTable_Enum* e = subs[field->submsg_index].subenum; + if (!_upb_Decoder_CheckEnum(d, ptr, msg, e, field, val)) return ptr; + void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->size * 4, void); + arr->size++; + memcpy(mem, val, 4); + return ptr; +} - if (!f) { - if ((d->options & upb_JsonDecode_IgnoreUnknown) == 0) { - jsondec_errf(d, "No such field: " UPB_STRINGVIEW_FORMAT, - UPB_STRINGVIEW_ARGS(name)); +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeFixedPacked( + upb_Decoder* d, const char* ptr, upb_Array* arr, wireval* val, + const upb_MiniTable_Field* field, int lg2) { + int mask = (1 << lg2) - 1; + size_t count = val->size >> lg2; + if ((val->size & mask) != 0) { + // Length isn't a round multiple of elem size. + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + } + _upb_Decoder_Reserve(d, arr, count); + void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << lg2, void); + arr->size += count; + // Note: if/when the decoder supports multi-buffer input, we will need to + // handle buffer seams here. + if (_upb_IsLittleEndian()) { + memcpy(mem, ptr, val->size); + ptr += val->size; + } else { + const char* end = ptr + val->size; + char* dst = mem; + while (ptr < end) { + if (lg2 == 2) { + uint32_t val; + memcpy(&val, ptr, sizeof(val)); + val = _upb_BigEndian_Swap32(val); + memcpy(dst, &val, sizeof(val)); + } else { + UPB_ASSERT(lg2 == 3); + uint64_t val; + memcpy(&val, ptr, sizeof(val)); + val = _upb_BigEndian_Swap64(val); + memcpy(dst, &val, sizeof(val)); + } + ptr += 1 << lg2; + dst += 1 << lg2; } - jsondec_skipval(d); - return; } - if (jsondec_peek(d) == JD_NULL && !jsondec_isvalue(f)) { - /* JSON "null" indicates a default value, so no need to set anything. */ - jsondec_null(d); - return; - } + return ptr; +} - if (upb_FieldDef_RealContainingOneof(f) && - upb_Message_WhichOneof(msg, upb_FieldDef_ContainingOneof(f))) { - jsondec_err(d, "More than one field for this oneof."); +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeVarintPacked( + upb_Decoder* d, const char* ptr, upb_Array* arr, wireval* val, + const upb_MiniTable_Field* field, int lg2) { + int scale = 1 << lg2; + int saved_limit = _upb_Decoder_PushLimit(d, ptr, val->size); + char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << lg2, void); + while (!_upb_Decoder_IsDone(d, &ptr)) { + wireval elem; + ptr = _upb_Decoder_DecodeVarint(d, ptr, &elem.uint64_val); + _upb_Decoder_Munge(field->descriptortype, &elem); + if (_upb_Decoder_Reserve(d, arr, 1)) { + out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << lg2, void); + } + arr->size++; + memcpy(out, &elem, scale); + out += scale; } + _upb_Decoder_PopLimit(d, ptr, saved_limit); + return ptr; +} - preserved = d->debug_field; - d->debug_field = f; - - if (upb_FieldDef_IsMap(f)) { - jsondec_map(d, msg, f); - } else if (upb_FieldDef_IsRepeated(f)) { - jsondec_array(d, msg, f); - } else if (upb_FieldDef_IsSubMessage(f)) { - upb_Message* submsg = upb_Message_Mutable(msg, f, d->arena).msg; - const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); - jsondec_tomsg(d, submsg, subm); - } else { - upb_MessageValue val = jsondec_value(d, f); - upb_Message_Set(msg, f, val, d->arena); +UPB_NOINLINE +static const char* _upb_Decoder_DecodeEnumPacked( + upb_Decoder* d, const char* ptr, upb_Message* msg, upb_Array* arr, + const upb_MiniTable_Sub* subs, const upb_MiniTable_Field* field, + wireval* val) { + const upb_MiniTable_Enum* e = subs[field->submsg_index].subenum; + int saved_limit = _upb_Decoder_PushLimit(d, ptr, val->size); + char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size * 4, void); + while (!_upb_Decoder_IsDone(d, &ptr)) { + wireval elem; + ptr = _upb_Decoder_DecodeVarint(d, ptr, &elem.uint64_val); + _upb_Decoder_MungeInt32(&elem); + if (!_upb_Decoder_CheckEnum(d, ptr, msg, e, field, &elem)) { + continue; + } + if (_upb_Decoder_Reserve(d, arr, 1)) { + out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size * 4, void); + } + arr->size++; + memcpy(out, &elem, 4); + out += 4; } + _upb_Decoder_PopLimit(d, ptr, saved_limit); + return ptr; +} - d->debug_field = preserved; +upb_Array* _upb_Decoder_CreateArray(upb_Decoder* d, + const upb_MiniTable_Field* field) { + /* Maps descriptor type -> elem_size_lg2. */ + static const uint8_t kElemSizeLg2[] = { + [0] = -1, // invalid descriptor type + [kUpb_FieldType_Double] = 3, + [kUpb_FieldType_Float] = 2, + [kUpb_FieldType_Int64] = 3, + [kUpb_FieldType_UInt64] = 3, + [kUpb_FieldType_Int32] = 2, + [kUpb_FieldType_Fixed64] = 3, + [kUpb_FieldType_Fixed32] = 2, + [kUpb_FieldType_Bool] = 0, + [kUpb_FieldType_String] = UPB_SIZE(3, 4), + [kUpb_FieldType_Group] = UPB_SIZE(2, 3), + [kUpb_FieldType_Message] = UPB_SIZE(2, 3), + [kUpb_FieldType_Bytes] = UPB_SIZE(3, 4), + [kUpb_FieldType_UInt32] = 2, + [kUpb_FieldType_Enum] = 2, + [kUpb_FieldType_SFixed32] = 2, + [kUpb_FieldType_SFixed64] = 3, + [kUpb_FieldType_SInt32] = 2, + [kUpb_FieldType_SInt64] = 3, + }; + + size_t lg2 = kElemSizeLg2[field->descriptortype]; + upb_Array* ret = _upb_Array_New(&d->arena, 4, lg2); + if (!ret) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + return ret; } -static void jsondec_object(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - jsondec_objstart(d); - while (jsondec_objnext(d)) { - jsondec_field(d, msg, m); +static const char* _upb_Decoder_DecodeToArray(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field, + wireval* val, int op) { + upb_Array** arrp = UPB_PTR_AT(msg, field->offset, void); + upb_Array* arr = *arrp; + void* mem; + + if (arr) { + _upb_Decoder_Reserve(d, arr, 1); + } else { + arr = _upb_Decoder_CreateArray(d, field); + *arrp = arr; } - jsondec_objend(d); -} -static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f) { - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Bool: - return jsondec_bool(d, f); - case kUpb_CType_Float: - case kUpb_CType_Double: - return jsondec_double(d, f); - case kUpb_CType_UInt32: - case kUpb_CType_UInt64: - return jsondec_uint(d, f); - case kUpb_CType_Int32: - case kUpb_CType_Int64: - return jsondec_int(d, f); - case kUpb_CType_String: - case kUpb_CType_Bytes: - return jsondec_strfield(d, f); - case kUpb_CType_Enum: - return jsondec_enum(d, f); - case kUpb_CType_Message: - return jsondec_msg(d, f); + switch (op) { + case kUpb_DecodeOp_Scalar1Byte: + case kUpb_DecodeOp_Scalar4Byte: + case kUpb_DecodeOp_Scalar8Byte: + /* Append scalar value. */ + mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << op, void); + arr->size++; + memcpy(mem, val, 1 << op); + return ptr; + case kUpb_DecodeOp_String: + _upb_Decoder_VerifyUtf8(d, ptr, val->size); + /* Fallthrough. */ + case kUpb_DecodeOp_Bytes: { + /* Append bytes. */ + upb_StringView* str = (upb_StringView*)_upb_array_ptr(arr) + arr->size; + arr->size++; + return _upb_Decoder_ReadString(d, ptr, val->size, str); + } + case kUpb_DecodeOp_SubMessage: { + /* Append submessage / group. */ + upb_Message* submsg = _upb_Decoder_NewSubMessage(d, subs, field); + *UPB_PTR_AT(_upb_array_ptr(arr), arr->size * sizeof(void*), + upb_Message*) = submsg; + arr->size++; + if (UPB_UNLIKELY(field->descriptortype == kUpb_FieldType_Group)) { + return _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, subs, field); + } else { + return _upb_Decoder_DecodeSubMessage(d, ptr, submsg, subs, field, + val->size); + } + } + case OP_FIXPCK_LG2(2): + case OP_FIXPCK_LG2(3): + return _upb_Decoder_DecodeFixedPacked(d, ptr, arr, val, field, + op - OP_FIXPCK_LG2(0)); + case OP_VARPCK_LG2(0): + case OP_VARPCK_LG2(2): + case OP_VARPCK_LG2(3): + return _upb_Decoder_DecodeVarintPacked(d, ptr, arr, val, field, + op - OP_VARPCK_LG2(0)); + case kUpb_DecodeOp_Enum: + return _upb_Decoder_DecodeEnumArray(d, ptr, msg, arr, subs, field, val); + case kUpb_DecodeOp_PackedEnum: + return _upb_Decoder_DecodeEnumPacked(d, ptr, msg, arr, subs, field, val); default: UPB_UNREACHABLE(); } } -/* Well-known types ***********************************************************/ +upb_Map* _upb_Decoder_CreateMap(upb_Decoder* d, const upb_MiniTable* entry) { + /* Maps descriptor type -> upb map size. */ + static const uint8_t kSizeInMap[] = { + [0] = -1, // invalid descriptor type */ + [kUpb_FieldType_Double] = 8, + [kUpb_FieldType_Float] = 4, + [kUpb_FieldType_Int64] = 8, + [kUpb_FieldType_UInt64] = 8, + [kUpb_FieldType_Int32] = 4, + [kUpb_FieldType_Fixed64] = 8, + [kUpb_FieldType_Fixed32] = 4, + [kUpb_FieldType_Bool] = 1, + [kUpb_FieldType_String] = UPB_MAPTYPE_STRING, + [kUpb_FieldType_Group] = sizeof(void*), + [kUpb_FieldType_Message] = sizeof(void*), + [kUpb_FieldType_Bytes] = UPB_MAPTYPE_STRING, + [kUpb_FieldType_UInt32] = 4, + [kUpb_FieldType_Enum] = 4, + [kUpb_FieldType_SFixed32] = 4, + [kUpb_FieldType_SFixed64] = 8, + [kUpb_FieldType_SInt32] = 4, + [kUpb_FieldType_SInt64] = 8, + }; -static int jsondec_tsdigits(jsondec* d, const char** ptr, size_t digits, - const char* after) { - uint64_t val; - const char* p = *ptr; - const char* end = p + digits; - size_t after_len = after ? strlen(after) : 0; + const upb_MiniTable_Field* key_field = &entry->fields[0]; + const upb_MiniTable_Field* val_field = &entry->fields[1]; + char key_size = kSizeInMap[key_field->descriptortype]; + char val_size = kSizeInMap[val_field->descriptortype]; + UPB_ASSERT(key_field->offset == 0); + UPB_ASSERT(val_field->offset == sizeof(upb_StringView)); + upb_Map* ret = _upb_Map_New(&d->arena, key_size, val_size); + if (!ret) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + return ret; +} - UPB_ASSERT(digits <= 9); /* int can't overflow. */ +static const char* _upb_Decoder_DecodeToMap(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field, + wireval* val) { + upb_Map** map_p = UPB_PTR_AT(msg, field->offset, upb_Map*); + upb_Map* map = *map_p; + upb_MapEntry ent; + const upb_MiniTable* entry = subs[field->submsg_index].submsg; - if (jsondec_buftouint64(d, p, end, &val) != end || - (after_len && memcmp(end, after, after_len) != 0)) { - jsondec_err(d, "Malformed timestamp"); + if (!map) { + map = _upb_Decoder_CreateMap(d, entry); + *map_p = map; } - UPB_ASSERT(val < INT_MAX); + /* Parse map entry. */ + memset(&ent, 0, sizeof(ent)); - *ptr = end + after_len; - return (int)val; + if (entry->fields[1].descriptortype == kUpb_FieldType_Message || + entry->fields[1].descriptortype == kUpb_FieldType_Group) { + /* Create proactively to handle the case where it doesn't appear. */ + ent.v.val = + upb_value_ptr(_upb_Message_New(entry->subs[0].submsg, &d->arena)); + } + + const char* start = ptr; + ptr = _upb_Decoder_DecodeSubMessage(d, ptr, &ent.k, subs, field, val->size); + // check if ent had any unknown fields + size_t size; + upb_Message_GetUnknown(&ent.k, &size); + if (size != 0) { + uint32_t tag = ((uint32_t)field->number << 3) | kUpb_WireType_Delimited; + _upb_Decoder_AddUnknownVarints(d, msg, tag, (uint32_t)(ptr - start)); + if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + } else { + if (_upb_Map_Insert(map, &ent.k, map->key_size, &ent.v, map->val_size, + &d->arena) == _kUpb_MapInsertStatus_OutOfMemory) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + } + return ptr; } -static int jsondec_nanos(jsondec* d, const char** ptr, const char* end) { - uint64_t nanos = 0; - const char* p = *ptr; +static const char* _upb_Decoder_DecodeToSubMessage( + upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTable_Sub* subs, const upb_MiniTable_Field* field, + wireval* val, int op) { + void* mem = UPB_PTR_AT(msg, field->offset, void); + int type = field->descriptortype; - if (p != end && *p == '.') { - const char* nano_end = jsondec_buftouint64(d, p + 1, end, &nanos); - int digits = (int)(nano_end - p - 1); - int exp_lg10 = 9 - digits; - if (digits > 9) { - jsondec_err(d, "Too many digits for partial seconds"); + if (UPB_UNLIKELY(op == kUpb_DecodeOp_Enum) && + !_upb_Decoder_CheckEnum(d, ptr, msg, subs[field->submsg_index].subenum, + field, val)) { + return ptr; + } + + /* Set presence if necessary. */ + if (field->presence > 0) { + _upb_sethas_field(msg, field); + } else if (field->presence < 0) { + /* Oneof case */ + uint32_t* oneof_case = _upb_oneofcase_field(msg, field); + if (op == kUpb_DecodeOp_SubMessage && *oneof_case != field->number) { + memset(mem, 0, sizeof(void*)); } - while (exp_lg10--) nanos *= 10; - *ptr = nano_end; + *oneof_case = field->number; } - UPB_ASSERT(nanos < INT_MAX); + /* Store into message. */ + switch (op) { + case kUpb_DecodeOp_SubMessage: { + upb_Message** submsgp = mem; + upb_Message* submsg = *submsgp; + if (!submsg) { + submsg = _upb_Decoder_NewSubMessage(d, subs, field); + *submsgp = submsg; + } + if (UPB_UNLIKELY(type == kUpb_FieldType_Group)) { + ptr = _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, subs, field); + } else { + ptr = _upb_Decoder_DecodeSubMessage(d, ptr, submsg, subs, field, + val->size); + } + break; + } + case kUpb_DecodeOp_String: + _upb_Decoder_VerifyUtf8(d, ptr, val->size); + /* Fallthrough. */ + case kUpb_DecodeOp_Bytes: + return _upb_Decoder_ReadString(d, ptr, val->size, mem); + case kUpb_DecodeOp_Scalar8Byte: + memcpy(mem, val, 8); + break; + case kUpb_DecodeOp_Enum: + case kUpb_DecodeOp_Scalar4Byte: + memcpy(mem, val, 4); + break; + case kUpb_DecodeOp_Scalar1Byte: + memcpy(mem, val, 1); + break; + default: + UPB_UNREACHABLE(); + } - return (int)nanos; + return ptr; } -/* jsondec_epochdays(1970, 1, 1) == 1970-01-01 == 0. */ -int jsondec_epochdays(int y, int m, int d) { - const uint32_t year_base = 4800; /* Before min year, multiple of 400. */ - const uint32_t m_adj = m - 3; /* March-based month. */ - const uint32_t carry = m_adj > (uint32_t)m ? 1 : 0; - const uint32_t adjust = carry ? 12 : 0; - const uint32_t y_adj = y + year_base - carry; - const uint32_t month_days = ((m_adj + adjust) * 62719 + 769) / 2048; - const uint32_t leap_days = y_adj / 4 - y_adj / 100 + y_adj / 400; - return y_adj * 365 + leap_days + month_days + (d - 1) - 2472632; +UPB_NOINLINE +const char* _upb_Decoder_CheckRequired(upb_Decoder* d, const char* ptr, + const upb_Message* msg, + const upb_MiniTable* l) { + assert(l->required_count); + if (UPB_LIKELY((d->options & kUpb_DecodeOption_CheckRequired) == 0)) { + return ptr; + } + uint64_t msg_head; + memcpy(&msg_head, msg, 8); + msg_head = _upb_BigEndian_Swap64(msg_head); + if (upb_MiniTable_requiredmask(l) & ~msg_head) { + d->missing_required = true; + } + return ptr; } -static int64_t jsondec_unixtime(int y, int m, int d, int h, int min, int s) { - return (int64_t)jsondec_epochdays(y, m, d) * 86400 + h * 3600 + min * 60 + s; +UPB_FORCEINLINE +static bool _upb_Decoder_TryFastDispatch(upb_Decoder* d, const char** ptr, + upb_Message* msg, + const upb_MiniTable* layout) { +#if UPB_FASTTABLE + if (layout && layout->table_mask != (unsigned char)-1) { + uint16_t tag = _upb_FastDecoder_LoadTag(*ptr); + intptr_t table = decode_totable(layout); + *ptr = _upb_FastDecoder_TagDispatch(d, *ptr, msg, table, 0, tag); + return true; + } +#endif + return false; } -static void jsondec_timestamp(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - upb_MessageValue seconds; - upb_MessageValue nanos; - upb_StringView str = jsondec_string(d); - const char* ptr = str.data; - const char* end = ptr + str.size; +static const char* upb_Decoder_SkipField(upb_Decoder* d, const char* ptr, + uint32_t tag) { + int field_number = tag >> 3; + int wire_type = tag & 7; + switch (wire_type) { + case kUpb_WireType_Varint: { + uint64_t val; + return _upb_Decoder_DecodeVarint(d, ptr, &val); + } + case kUpb_WireType_64Bit: + return ptr + 8; + case kUpb_WireType_32Bit: + return ptr + 4; + case kUpb_WireType_Delimited: { + uint32_t size; + ptr = upb_Decoder_DecodeSize(d, ptr, &size); + return ptr + size; + } + case kUpb_WireType_StartGroup: + return _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); + default: + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + } +} - if (str.size < 20) goto malformed; +enum { + kStartItemTag = ((1 << 3) | kUpb_WireType_StartGroup), + kEndItemTag = ((1 << 3) | kUpb_WireType_EndGroup), + kTypeIdTag = ((2 << 3) | kUpb_WireType_Varint), + kMessageTag = ((3 << 3) | kUpb_WireType_Delimited), +}; - { - /* 1972-01-01T01:00:00 */ - int year = jsondec_tsdigits(d, &ptr, 4, "-"); - int mon = jsondec_tsdigits(d, &ptr, 2, "-"); - int day = jsondec_tsdigits(d, &ptr, 2, "T"); - int hour = jsondec_tsdigits(d, &ptr, 2, ":"); - int min = jsondec_tsdigits(d, &ptr, 2, ":"); - int sec = jsondec_tsdigits(d, &ptr, 2, NULL); +static void upb_Decoder_AddKnownMessageSetItem( + upb_Decoder* d, upb_Message* msg, const upb_MiniTable_Extension* item_mt, + const char* data, uint32_t size) { + upb_Message_Extension* ext = + _upb_Message_GetOrCreateExtension(msg, item_mt, &d->arena); + if (UPB_UNLIKELY(!ext)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + upb_Message* submsg = + _upb_Decoder_NewSubMessage(d, &ext->ext->sub, &ext->ext->field); + upb_DecodeStatus status = upb_Decode(data, size, submsg, item_mt->sub.submsg, + d->extreg, d->options, &d->arena); + memcpy(&ext->data, &submsg, sizeof(submsg)); + if (status != kUpb_DecodeStatus_Ok) _upb_Decoder_ErrorJmp(d, status); +} + +static void upb_Decoder_AddUnknownMessageSetItem(upb_Decoder* d, + upb_Message* msg, + uint32_t type_id, + const char* message_data, + uint32_t message_size) { + char buf[60]; + char* ptr = buf; + ptr = upb_Decoder_EncodeVarint32(kStartItemTag, ptr); + ptr = upb_Decoder_EncodeVarint32(kTypeIdTag, ptr); + ptr = upb_Decoder_EncodeVarint32(type_id, ptr); + ptr = upb_Decoder_EncodeVarint32(kMessageTag, ptr); + ptr = upb_Decoder_EncodeVarint32(message_size, ptr); + char* split = ptr; + + ptr = upb_Decoder_EncodeVarint32(kEndItemTag, ptr); + char* end = ptr; + + if (!_upb_Message_AddUnknown(msg, buf, split - buf, &d->arena) || + !_upb_Message_AddUnknown(msg, message_data, message_size, &d->arena) || + !_upb_Message_AddUnknown(msg, split, end - split, &d->arena)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } +} + +static void upb_Decoder_AddMessageSetItem(upb_Decoder* d, upb_Message* msg, + const upb_MiniTable* layout, + uint32_t type_id, const char* data, + uint32_t size) { + const upb_MiniTable_Extension* item_mt = + _upb_extreg_get(d->extreg, layout, type_id); + if (item_mt) { + upb_Decoder_AddKnownMessageSetItem(d, msg, item_mt, data, size); + } else { + upb_Decoder_AddUnknownMessageSetItem(d, msg, type_id, data, size); + } +} - seconds.int64_val = jsondec_unixtime(year, mon, day, hour, min, sec); +static const char* upb_Decoder_DecodeMessageSetItem( + upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTable* layout) { + uint32_t type_id = 0; + upb_StringView preserved = {NULL, 0}; + typedef enum { + kUpb_HaveId = 1 << 0, + kUpb_HavePayload = 1 << 1, + } StateMask; + StateMask state_mask = 0; + while (!_upb_Decoder_IsDone(d, &ptr)) { + uint32_t tag; + ptr = _upb_Decoder_DecodeTag(d, ptr, &tag); + switch (tag) { + case kEndItemTag: + return ptr; + case kTypeIdTag: { + uint64_t tmp; + ptr = _upb_Decoder_DecodeVarint(d, ptr, &tmp); + if (state_mask & kUpb_HaveId) break; // Ignore dup. + state_mask |= kUpb_HaveId; + type_id = tmp; + if (state_mask & kUpb_HavePayload) { + upb_Decoder_AddMessageSetItem(d, msg, layout, type_id, preserved.data, + preserved.size); + } + break; + } + case kMessageTag: { + uint32_t size; + ptr = upb_Decoder_DecodeSize(d, ptr, &size); + const char* data = ptr; + ptr += size; + if (state_mask & kUpb_HavePayload) break; // Ignore dup. + state_mask |= kUpb_HavePayload; + if (state_mask & kUpb_HaveId) { + upb_Decoder_AddMessageSetItem(d, msg, layout, type_id, data, size); + } else { + // Out of order, we must preserve the payload. + preserved.data = data; + preserved.size = size; + } + break; + } + default: + // We do not preserve unexpected fields inside a message set item. + ptr = upb_Decoder_SkipField(d, ptr, tag); + break; + } } + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); +} - nanos.int32_val = jsondec_nanos(d, &ptr, end); +static const upb_MiniTable_Field* _upb_Decoder_FindField( + upb_Decoder* d, const upb_MiniTable* l, uint32_t field_number, + int* last_field_index) { + static upb_MiniTable_Field none = { + 0, 0, 0, 0, kUpb_FakeFieldType_FieldNotFound, 0}; + if (l == NULL) return &none; - { - /* [+-]08:00 or Z */ - int ofs_hour = 0; - int ofs_min = 0; - bool neg = false; + size_t idx = ((size_t)field_number) - 1; // 0 wraps to SIZE_MAX + if (idx < l->dense_below) { + /* Fastest case: index into dense fields. */ + goto found; + } - if (ptr == end) goto malformed; + if (l->dense_below < l->field_count) { + /* Linear search non-dense fields. Resume scanning from last_field_index + * since fields are usually in order. */ + int last = *last_field_index; + for (idx = last; idx < l->field_count; idx++) { + if (l->fields[idx].number == field_number) { + goto found; + } + } - switch (*ptr++) { - case '-': - neg = true; - /* fallthrough */ - case '+': - if ((end - ptr) != 5) goto malformed; - ofs_hour = jsondec_tsdigits(d, &ptr, 2, ":"); - ofs_min = jsondec_tsdigits(d, &ptr, 2, NULL); - ofs_min = ((ofs_hour * 60) + ofs_min) * 60; - seconds.int64_val += (neg ? ofs_min : -ofs_min); - break; - case 'Z': - if (ptr != end) goto malformed; + for (idx = l->dense_below; idx < last; idx++) { + if (l->fields[idx].number == field_number) { + goto found; + } + } + } + + if (d->extreg) { + switch (l->ext) { + case kUpb_ExtMode_Extendable: { + const upb_MiniTable_Extension* ext = + _upb_extreg_get(d->extreg, l, field_number); + if (ext) return &ext->field; + break; + } + case kUpb_ExtMode_IsMessageSet: + if (field_number == _UPB_MSGSET_ITEM) { + static upb_MiniTable_Field item = { + 0, 0, 0, 0, kUpb_FakeFieldType_MessageSetItem, 0}; + return &item; + } break; - default: - goto malformed; } } - if (seconds.int64_val < -62135596800) { - jsondec_err(d, "Timestamp out of range"); - } - - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, - d->arena); - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); - return; + return &none; /* Unknown field. */ -malformed: - jsondec_err(d, "Malformed timestamp"); +found: + UPB_ASSERT(l->fields[idx].number == field_number); + *last_field_index = idx; + return &l->fields[idx]; } -static void jsondec_duration(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - upb_MessageValue seconds; - upb_MessageValue nanos; - upb_StringView str = jsondec_string(d); - const char* ptr = str.data; - const char* end = ptr + str.size; - const int64_t max = (uint64_t)3652500 * 86400; - - /* "3.000000001s", "3s", etc. */ - ptr = jsondec_buftoint64(d, ptr, end, &seconds.int64_val); - nanos.int32_val = jsondec_nanos(d, &ptr, end); +int _upb_Decoder_GetVarintOp(const upb_MiniTable_Field* field) { + static const int8_t kVarintOps[] = { + [kUpb_FakeFieldType_FieldNotFound] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Double] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Float] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Int64] = kUpb_DecodeOp_Scalar8Byte, + [kUpb_FieldType_UInt64] = kUpb_DecodeOp_Scalar8Byte, + [kUpb_FieldType_Int32] = kUpb_DecodeOp_Scalar4Byte, + [kUpb_FieldType_Fixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Fixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Bool] = kUpb_DecodeOp_Scalar1Byte, + [kUpb_FieldType_String] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Message] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Bytes] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_UInt32] = kUpb_DecodeOp_Scalar4Byte, + [kUpb_FieldType_Enum] = kUpb_DecodeOp_Enum, + [kUpb_FieldType_SFixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SFixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SInt32] = kUpb_DecodeOp_Scalar4Byte, + [kUpb_FieldType_SInt64] = kUpb_DecodeOp_Scalar8Byte, + [kUpb_FakeFieldType_MessageSetItem] = kUpb_DecodeOp_UnknownField, + }; - if (end - ptr != 1 || *ptr != 's') { - jsondec_err(d, "Malformed duration"); - } + return kVarintOps[field->descriptortype]; +} + +int _upb_Decoder_GetDelimitedOp(const upb_MiniTable* mt, + const upb_MiniTable_Field* field) { + enum { kRepeatedBase = 19 }; + + static const int8_t kDelimitedOps[] = { + /* For non-repeated field type. */ + [kUpb_FakeFieldType_FieldNotFound] = + kUpb_DecodeOp_UnknownField, // Field not found. + [kUpb_FieldType_Double] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Float] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Int64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_UInt64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Int32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Fixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Fixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Bool] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_String] = kUpb_DecodeOp_String, + [kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Message] = kUpb_DecodeOp_SubMessage, + [kUpb_FieldType_Bytes] = kUpb_DecodeOp_Bytes, + [kUpb_FieldType_UInt32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Enum] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SFixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SFixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SInt32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SInt64] = kUpb_DecodeOp_UnknownField, + [kUpb_FakeFieldType_MessageSetItem] = kUpb_DecodeOp_UnknownField, + // For repeated field type. */ + [kRepeatedBase + kUpb_FieldType_Double] = OP_FIXPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_Float] = OP_FIXPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Int64] = OP_VARPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_UInt64] = OP_VARPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_Int32] = OP_VARPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Fixed64] = OP_FIXPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_Fixed32] = OP_FIXPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Bool] = OP_VARPCK_LG2(0), + [kRepeatedBase + kUpb_FieldType_String] = kUpb_DecodeOp_String, + [kRepeatedBase + kUpb_FieldType_Group] = kUpb_DecodeOp_SubMessage, + [kRepeatedBase + kUpb_FieldType_Message] = kUpb_DecodeOp_SubMessage, + [kRepeatedBase + kUpb_FieldType_Bytes] = kUpb_DecodeOp_Bytes, + [kRepeatedBase + kUpb_FieldType_UInt32] = OP_VARPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Enum] = kUpb_DecodeOp_PackedEnum, + [kRepeatedBase + kUpb_FieldType_SFixed32] = OP_FIXPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_SFixed64] = OP_FIXPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_SInt32] = OP_VARPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_SInt64] = OP_VARPCK_LG2(3), + // Omitting kUpb_FakeFieldType_MessageSetItem, because we never emit a + // repeated msgset type + }; - if (seconds.int64_val < -max || seconds.int64_val > max) { - jsondec_err(d, "Duration out of range"); - } + int ndx = field->descriptortype; + if (upb_FieldMode_Get(field) == kUpb_FieldMode_Array) ndx += kRepeatedBase; + int op = kDelimitedOps[ndx]; - if (seconds.int64_val < 0) { - nanos.int32_val = -nanos.int32_val; + // If sub-message is not linked, treat as unknown. + if (op == kUpb_DecodeOp_SubMessage && + !(field->mode & kUpb_LabelFlags_IsExtension)) { + const upb_MiniTable_Sub* sub = &mt->subs[field->submsg_index]; + if (!sub->submsg) { + op = kUpb_DecodeOp_UnknownField; + } } - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, - d->arena); - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); + return op; } -static void jsondec_listvalue(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(values_f); - upb_Array* values = upb_Message_Mutable(msg, values_f, d->arena).array; +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeWireValue( + upb_Decoder* d, const char* ptr, const upb_MiniTable* mt, + const upb_MiniTable_Field* field, int wire_type, wireval* val, int* op) { + static const unsigned kFixed32OkMask = (1 << kUpb_FieldType_Float) | + (1 << kUpb_FieldType_Fixed32) | + (1 << kUpb_FieldType_SFixed32); - jsondec_arrstart(d); - while (jsondec_arrnext(d)) { - upb_Message* value_msg = upb_Message_New(value_m, d->arena); - upb_MessageValue value; - value.msg_val = value_msg; - upb_Array_Append(values, value, d->arena); - jsondec_wellknownvalue(d, value_msg, value_m); + static const unsigned kFixed64OkMask = (1 << kUpb_FieldType_Double) | + (1 << kUpb_FieldType_Fixed64) | + (1 << kUpb_FieldType_SFixed64); + + switch (wire_type) { + case kUpb_WireType_Varint: + ptr = _upb_Decoder_DecodeVarint(d, ptr, &val->uint64_val); + *op = _upb_Decoder_GetVarintOp(field); + _upb_Decoder_Munge(field->descriptortype, val); + return ptr; + case kUpb_WireType_32Bit: + memcpy(&val->uint32_val, ptr, 4); + val->uint32_val = _upb_BigEndian_Swap32(val->uint32_val); + *op = kUpb_DecodeOp_Scalar4Byte; + if (((1 << field->descriptortype) & kFixed32OkMask) == 0) { + *op = kUpb_DecodeOp_UnknownField; + } + return ptr + 4; + case kUpb_WireType_64Bit: + memcpy(&val->uint64_val, ptr, 8); + val->uint64_val = _upb_BigEndian_Swap64(val->uint64_val); + *op = kUpb_DecodeOp_Scalar8Byte; + if (((1 << field->descriptortype) & kFixed64OkMask) == 0) { + *op = kUpb_DecodeOp_UnknownField; + } + return ptr + 8; + case kUpb_WireType_Delimited: + ptr = upb_Decoder_DecodeSize(d, ptr, &val->size); + *op = _upb_Decoder_GetDelimitedOp(mt, field); + return ptr; + case kUpb_WireType_StartGroup: + val->uint32_val = field->number; + if (field->descriptortype == kUpb_FieldType_Group) { + *op = kUpb_DecodeOp_SubMessage; + } else if (field->descriptortype == kUpb_FakeFieldType_MessageSetItem) { + *op = kUpb_DecodeOp_MessageSetItem; + } else { + *op = kUpb_DecodeOp_UnknownField; + } + return ptr; + default: + break; } - jsondec_arrend(d); + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); } -static void jsondec_struct(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); - const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(value_f); - upb_Map* fields = upb_Message_Mutable(msg, fields_f, d->arena).map; +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeKnownField( + upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTable* layout, const upb_MiniTable_Field* field, int op, + wireval* val) { + const upb_MiniTable_Sub* subs = layout->subs; + uint8_t mode = field->mode; - jsondec_objstart(d); - while (jsondec_objnext(d)) { - upb_MessageValue key, value; - upb_Message* value_msg = upb_Message_New(value_m, d->arena); - key.str_val = jsondec_string(d); - value.msg_val = value_msg; - upb_Map_Set(fields, key, value, d->arena); - jsondec_entrysep(d); - jsondec_wellknownvalue(d, value_msg, value_m); + if (UPB_UNLIKELY(mode & kUpb_LabelFlags_IsExtension)) { + const upb_MiniTable_Extension* ext_layout = + (const upb_MiniTable_Extension*)field; + upb_Message_Extension* ext = + _upb_Message_GetOrCreateExtension(msg, ext_layout, &d->arena); + if (UPB_UNLIKELY(!ext)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + d->unknown_msg = msg; + msg = &ext->data; + subs = &ext->ext->sub; } - jsondec_objend(d); -} - -static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - upb_MessageValue val; - const upb_FieldDef* f; - upb_Message* submsg; - switch (jsondec_peek(d)) { - case JD_NUMBER: - /* double number_value = 2; */ - f = upb_MessageDef_FindFieldByNumber(m, 2); - val.double_val = jsondec_number(d); - break; - case JD_STRING: - /* string string_value = 3; */ - f = upb_MessageDef_FindFieldByNumber(m, 3); - val.str_val = jsondec_string(d); - break; - case JD_FALSE: - /* bool bool_value = 4; */ - f = upb_MessageDef_FindFieldByNumber(m, 4); - val.bool_val = false; - jsondec_false(d); - break; - case JD_TRUE: - /* bool bool_value = 4; */ - f = upb_MessageDef_FindFieldByNumber(m, 4); - val.bool_val = true; - jsondec_true(d); - break; - case JD_NULL: - /* NullValue null_value = 1; */ - f = upb_MessageDef_FindFieldByNumber(m, 1); - val.int32_val = 0; - jsondec_null(d); - break; - /* Note: these cases return, because upb_Message_Mutable() is enough. */ - case JD_OBJECT: - /* Struct struct_value = 5; */ - f = upb_MessageDef_FindFieldByNumber(m, 5); - submsg = upb_Message_Mutable(msg, f, d->arena).msg; - jsondec_struct(d, submsg, upb_FieldDef_MessageSubDef(f)); - return; - case JD_ARRAY: - /* ListValue list_value = 6; */ - f = upb_MessageDef_FindFieldByNumber(m, 6); - submsg = upb_Message_Mutable(msg, f, d->arena).msg; - jsondec_listvalue(d, submsg, upb_FieldDef_MessageSubDef(f)); - return; + switch (mode & kUpb_FieldMode_Mask) { + case kUpb_FieldMode_Array: + return _upb_Decoder_DecodeToArray(d, ptr, msg, subs, field, val, op); + case kUpb_FieldMode_Map: + return _upb_Decoder_DecodeToMap(d, ptr, msg, subs, field, val); + case kUpb_FieldMode_Scalar: + return _upb_Decoder_DecodeToSubMessage(d, ptr, msg, subs, field, val, op); default: UPB_UNREACHABLE(); } +} - upb_Message_Set(msg, f, val, d->arena); +static const char* _upb_Decoder_ReverseSkipVarint(const char* ptr, + uint32_t val) { + uint32_t seen = 0; + do { + ptr--; + seen <<= 7; + seen |= *ptr & 0x7f; + } while (seen != val); + return ptr; } -static upb_StringView jsondec_mask(jsondec* d, const char* buf, - const char* end) { - /* FieldMask fields grow due to inserted '_' characters, so we can't do the - * transform in place. */ - const char* ptr = buf; - upb_StringView ret; - char* out; +static const char* _upb_Decoder_DecodeUnknownField(upb_Decoder* d, + const char* ptr, + upb_Message* msg, + int field_number, + int wire_type, wireval val) { + if (field_number == 0) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); - ret.size = end - ptr; - while (ptr < end) { - ret.size += (*ptr >= 'A' && *ptr <= 'Z'); - ptr++; + // Since unknown fields are the uncommon case, we do a little extra work here + // to walk backwards through the buffer to find the field start. This frees + // up a register in the fast paths (when the field is known), which leads to + // significant speedups in benchmarks. + const char* start = ptr; + + if (wire_type == kUpb_WireType_Delimited) ptr += val.size; + if (msg) { + switch (wire_type) { + case kUpb_WireType_Varint: + case kUpb_WireType_Delimited: + start--; + while (start[-1] & 0x80) start--; + break; + case kUpb_WireType_32Bit: + start -= 4; + break; + case kUpb_WireType_64Bit: + start -= 8; + break; + default: + break; + } + + assert(start == d->debug_valstart); + uint32_t tag = ((uint32_t)field_number << 3) | wire_type; + start = _upb_Decoder_ReverseSkipVarint(start, tag); + assert(start == d->debug_tagstart); + + if (wire_type == kUpb_WireType_StartGroup) { + d->unknown = start; + d->unknown_msg = msg; + ptr = _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); + start = d->unknown; + d->unknown = NULL; + } + if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + } else if (wire_type == kUpb_WireType_StartGroup) { + ptr = _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); } + return ptr; +} + +UPB_NOINLINE +static const char* _upb_Decoder_DecodeMessage(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable* layout) { + int last_field_index = 0; + +#if UPB_FASTTABLE + // The first time we want to skip fast dispatch, because we may have just been + // invoked by the fast parser to handle a case that it bailed on. + if (!_upb_Decoder_IsDone(d, &ptr)) goto nofast; +#endif + + while (!_upb_Decoder_IsDone(d, &ptr)) { + uint32_t tag; + const upb_MiniTable_Field* field; + int field_number; + int wire_type; + wireval val; + int op; + + if (_upb_Decoder_TryFastDispatch(d, &ptr, msg, layout)) break; + +#if UPB_FASTTABLE + nofast: +#endif + +#ifndef NDEBUG + d->debug_tagstart = ptr; +#endif + + UPB_ASSERT(ptr < d->limit_ptr); + ptr = _upb_Decoder_DecodeTag(d, ptr, &tag); + field_number = tag >> 3; + wire_type = tag & 7; + +#ifndef NDEBUG + d->debug_valstart = ptr; +#endif + + if (wire_type == kUpb_WireType_EndGroup) { + d->end_group = field_number; + return ptr; + } - out = upb_Arena_Malloc(d->arena, ret.size); - ptr = buf; - ret.data = out; + field = _upb_Decoder_FindField(d, layout, field_number, &last_field_index); + ptr = _upb_Decoder_DecodeWireValue(d, ptr, layout, field, wire_type, &val, + &op); - while (ptr < end) { - char ch = *ptr++; - if (ch >= 'A' && ch <= 'Z') { - *out++ = '_'; - *out++ = ch + 32; - } else if (ch == '_') { - jsondec_err(d, "field mask may not contain '_'"); + if (op >= 0) { + ptr = _upb_Decoder_DecodeKnownField(d, ptr, msg, layout, field, op, &val); } else { - *out++ = ch; + switch (op) { + case kUpb_DecodeOp_UnknownField: + ptr = _upb_Decoder_DecodeUnknownField(d, ptr, msg, field_number, + wire_type, val); + break; + case kUpb_DecodeOp_MessageSetItem: + ptr = upb_Decoder_DecodeMessageSetItem(d, ptr, msg, layout); + break; + } } } - return ret; + return UPB_UNLIKELY(layout && layout->required_count) + ? _upb_Decoder_CheckRequired(d, ptr, msg, layout) + : ptr; } -static void jsondec_fieldmask(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - /* repeated string paths = 1; */ - const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); - upb_Array* arr = upb_Message_Mutable(msg, paths_f, d->arena).array; - upb_StringView str = jsondec_string(d); - const char* ptr = str.data; - const char* end = ptr + str.size; - upb_MessageValue val; - - while (ptr < end) { - const char* elem_end = memchr(ptr, ',', end - ptr); - if (elem_end) { - val.str_val = jsondec_mask(d, ptr, elem_end); - ptr = elem_end + 1; - } else { - val.str_val = jsondec_mask(d, ptr, end); - ptr = end; - } - upb_Array_Append(arr, val, d->arena); - } +const char* _upb_FastDecoder_DecodeGeneric(struct upb_Decoder* d, + const char* ptr, upb_Message* msg, + intptr_t table, uint64_t hasbits, + uint64_t data) { + (void)data; + *(uint32_t*)msg |= hasbits; + return _upb_Decoder_DecodeMessage(d, ptr, msg, decode_totablep(table)); } -static void jsondec_anyfield(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { - /* For regular types: {"@type": "[user type]", "f1": , "f2": } - * where f1, f2, etc. are the normal fields of this type. */ - jsondec_field(d, msg, m); - } else { - /* For well-known types: {"@type": "[well-known type]", "value": } - * where is whatever encoding the WKT normally uses. */ - upb_StringView str = jsondec_string(d); - jsondec_entrysep(d); - if (!jsondec_streql(str, "value")) { - jsondec_err(d, "Key for well-known type must be 'value'"); - } - jsondec_wellknown(d, msg, m); +static upb_DecodeStatus _upb_Decoder_DecodeTop(struct upb_Decoder* d, + const char* buf, void* msg, + const upb_MiniTable* l) { + if (!_upb_Decoder_TryFastDispatch(d, &buf, msg, l)) { + _upb_Decoder_DecodeMessage(d, buf, msg, l); } + if (d->end_group != DECODE_NOGROUP) return kUpb_DecodeStatus_Malformed; + if (d->missing_required) return kUpb_DecodeStatus_MissingRequired; + return kUpb_DecodeStatus_Ok; } -static const upb_MessageDef* jsondec_typeurl(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_MessageDef* type_m; - upb_StringView type_url = jsondec_string(d); - const char* end = type_url.data + type_url.size; - const char* ptr = end; - upb_MessageValue val; - - val.str_val = type_url; - upb_Message_Set(msg, type_url_f, val, d->arena); - - /* Find message name after the last '/' */ - while (ptr > type_url.data && *--ptr != '/') { - } +upb_DecodeStatus upb_Decode(const char* buf, size_t size, void* msg, + const upb_MiniTable* l, + const upb_ExtensionRegistry* extreg, int options, + upb_Arena* arena) { + upb_Decoder state; + unsigned depth = (unsigned)options >> 16; - if (ptr == type_url.data || ptr == end) { - jsondec_err(d, "Type url must have at least one '/' and non-empty host"); + if (size <= 16) { + memset(&state.patch, 0, 32); + if (size) memcpy(&state.patch, buf, size); + buf = state.patch; + state.end = buf + size; + state.limit = 0; + options &= ~kUpb_DecodeOption_AliasString; // Can't alias patch buf. + } else { + state.end = buf + size - 16; + state.limit = 16; } - ptr++; - type_m = upb_DefPool_FindMessageByNameWithSize(d->symtab, ptr, end - ptr); + state.extreg = extreg; + state.limit_ptr = state.end; + state.unknown = NULL; + state.depth = depth ? depth : 64; + state.end_group = DECODE_NOGROUP; + state.options = (uint16_t)options; + state.missing_required = false; + state.arena.head = arena->head; + state.arena.last_size = arena->last_size; + state.arena.cleanup_metadata = arena->cleanup_metadata; + state.arena.parent = arena; - if (!type_m) { - jsondec_err(d, "Type was not found"); + upb_DecodeStatus status = UPB_SETJMP(state.err); + if (UPB_LIKELY(status == kUpb_DecodeStatus_Ok)) { + status = _upb_Decoder_DecodeTop(&state, buf, msg, l); } - return type_m; + arena->head.ptr = state.arena.head.ptr; + arena->head.end = state.arena.head.end; + arena->cleanup_metadata = state.arena.cleanup_metadata; + return status; } -static void jsondec_any(jsondec* d, upb_Message* msg, const upb_MessageDef* m) { - /* string type_url = 1; - * bytes value = 2; */ - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); - upb_Message* any_msg; - const upb_MessageDef* any_m = NULL; - const char* pre_type_data = NULL; - const char* pre_type_end = NULL; - upb_MessageValue encoded; - - jsondec_objstart(d); +#undef OP_FIXPCK_LG2 +#undef OP_VARPCK_LG2 - /* Scan looking for "@type", which is not necessarily first. */ - while (!any_m && jsondec_objnext(d)) { - const char* start = d->ptr; - upb_StringView name = jsondec_string(d); - jsondec_entrysep(d); - if (jsondec_streql(name, "@type")) { - any_m = jsondec_typeurl(d, msg, m); - if (pre_type_data) { - pre_type_end = start; - while (*pre_type_end != ',') pre_type_end--; - } - } else { - if (!pre_type_data) pre_type_data = start; - jsondec_skipval(d); - } - } +/* We encode backwards, to avoid pre-computing lengths (one-pass encode). */ - if (!any_m) { - jsondec_err(d, "Any object didn't contain a '@type' field"); - } - any_msg = upb_Message_New(any_m, d->arena); +#include - if (pre_type_data) { - size_t len = pre_type_end - pre_type_data + 1; - char* tmp = upb_Arena_Malloc(d->arena, len); - const char* saved_ptr = d->ptr; - const char* saved_end = d->end; - memcpy(tmp, pre_type_data, len - 1); - tmp[len - 1] = '}'; - d->ptr = tmp; - d->end = tmp + len; - d->is_first = true; - while (jsondec_objnext(d)) { - jsondec_anyfield(d, any_msg, any_m); - } - d->ptr = saved_ptr; - d->end = saved_end; - } - while (jsondec_objnext(d)) { - jsondec_anyfield(d, any_msg, any_m); - } +// Must be last. - jsondec_objend(d); +#define UPB_PB_VARINT_MAX_LEN 10 - encoded.str_val.data = upb_Encode(any_msg, upb_MessageDef_MiniTable(any_m), 0, - d->arena, &encoded.str_val.size); - upb_Message_Set(msg, value_f, encoded, d->arena); +UPB_NOINLINE +static size_t encode_varint64(uint64_t val, char* buf) { + size_t i = 0; + do { + uint8_t byte = val & 0x7fU; + val >>= 7; + if (val) byte |= 0x80U; + buf[i++] = byte; + } while (val); + return i; } -static void jsondec_wrapper(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 1); - upb_MessageValue val = jsondec_value(d, value_f); - upb_Message_Set(msg, value_f, val, d->arena); +static uint32_t encode_zz32(int32_t n) { + return ((uint32_t)n << 1) ^ (n >> 31); } - -static void jsondec_wellknown(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - switch (upb_MessageDef_WellKnownType(m)) { - case kUpb_WellKnown_Any: - jsondec_any(d, msg, m); - break; - case kUpb_WellKnown_FieldMask: - jsondec_fieldmask(d, msg, m); - break; - case kUpb_WellKnown_Duration: - jsondec_duration(d, msg, m); - break; - case kUpb_WellKnown_Timestamp: - jsondec_timestamp(d, msg, m); - break; - case kUpb_WellKnown_Value: - jsondec_wellknownvalue(d, msg, m); - break; - case kUpb_WellKnown_ListValue: - jsondec_listvalue(d, msg, m); - break; - case kUpb_WellKnown_Struct: - jsondec_struct(d, msg, m); - break; - case kUpb_WellKnown_DoubleValue: - case kUpb_WellKnown_FloatValue: - case kUpb_WellKnown_Int64Value: - case kUpb_WellKnown_UInt64Value: - case kUpb_WellKnown_Int32Value: - case kUpb_WellKnown_UInt32Value: - case kUpb_WellKnown_StringValue: - case kUpb_WellKnown_BytesValue: - case kUpb_WellKnown_BoolValue: - jsondec_wrapper(d, msg, m); - break; - default: - UPB_UNREACHABLE(); - } +static uint64_t encode_zz64(int64_t n) { + return ((uint64_t)n << 1) ^ (n >> 63); } -bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, - const upb_MessageDef* m, const upb_DefPool* symtab, - int options, upb_Arena* arena, upb_Status* status) { - jsondec d; - - if (size == 0) return true; - - d.ptr = buf; - d.end = buf + size; - d.arena = arena; - d.symtab = symtab; - d.status = status; - d.options = options; - d.depth = 64; - d.line = 1; - d.line_begin = d.ptr; - d.debug_field = NULL; - d.is_first = false; +typedef struct { + jmp_buf err; + upb_Arena* arena; + char *buf, *ptr, *limit; + int options; + int depth; + _upb_mapsorter sorter; +} upb_encstate; - if (UPB_SETJMP(d.err)) return false; +static size_t upb_roundup_pow2(size_t bytes) { + size_t ret = 128; + while (ret < bytes) { + ret *= 2; + } + return ret; +} - jsondec_tomsg(&d, msg, m); - return true; +UPB_NORETURN static void encode_err(upb_encstate* e, upb_EncodeStatus s) { + UPB_LONGJMP(e->err, s); } -/** upb/json_encode.c ************************************************************/ +UPB_NOINLINE +static void encode_growbuffer(upb_encstate* e, size_t bytes) { + size_t old_size = e->limit - e->buf; + size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr)); + char* new_buf = upb_Arena_Realloc(e->arena, e->buf, old_size, new_size); -#include -#include -#include -#include -#include -#include -#include -#include + if (!new_buf) encode_err(e, kUpb_EncodeStatus_OutOfMemory); + // We want previous data at the end, realloc() put it at the beginning. + // TODO(salo): This is somewhat inefficient since we are copying twice. + // Maybe create a realloc() that copies to the end of the new buffer? + if (old_size > 0) { + memmove(new_buf + new_size - old_size, e->buf, old_size); + } -/* Must be last. */ + e->ptr = new_buf + new_size - (e->limit - e->ptr); + e->limit = new_buf + new_size; + e->buf = new_buf; -typedef struct { - char *buf, *ptr, *end; - size_t overflow; - int indent_depth; - int options; - const upb_DefPool* ext_pool; - jmp_buf err; - upb_Status* status; - upb_Arena* arena; -} jsonenc; + e->ptr -= bytes; +} -static void jsonenc_msg(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m); -static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, - const upb_FieldDef* f); -static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m); -static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m, bool first); -static void jsonenc_value(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m); +/* Call to ensure that at least "bytes" bytes are available for writing at + * e->ptr. Returns false if the bytes could not be allocated. */ +UPB_FORCEINLINE +static void encode_reserve(upb_encstate* e, size_t bytes) { + if ((size_t)(e->ptr - e->buf) < bytes) { + encode_growbuffer(e, bytes); + return; + } -UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) { - upb_Status_SetErrorMessage(e->status, msg); - longjmp(e->err, 1); + e->ptr -= bytes; } -UPB_PRINTF(2, 3) -UPB_NORETURN static void jsonenc_errf(jsonenc* e, const char* fmt, ...) { - va_list argp; - va_start(argp, fmt); - upb_Status_VSetErrorFormat(e->status, fmt, argp); - va_end(argp); - longjmp(e->err, 1); +/* Writes the given bytes to the buffer, handling reserve/advance. */ +static void encode_bytes(upb_encstate* e, const void* data, size_t len) { + if (len == 0) return; /* memcpy() with zero size is UB */ + encode_reserve(e, len); + memcpy(e->ptr, data, len); } -static upb_Arena* jsonenc_arena(jsonenc* e) { - /* Create lazily, since it's only needed for Any */ - if (!e->arena) { - e->arena = upb_Arena_New(); - } - return e->arena; +static void encode_fixed64(upb_encstate* e, uint64_t val) { + val = _upb_BigEndian_Swap64(val); + encode_bytes(e, &val, sizeof(uint64_t)); } -static void jsonenc_putbytes(jsonenc* e, const void* data, size_t len) { - size_t have = e->end - e->ptr; - if (UPB_LIKELY(have >= len)) { - memcpy(e->ptr, data, len); - e->ptr += len; +static void encode_fixed32(upb_encstate* e, uint32_t val) { + val = _upb_BigEndian_Swap32(val); + encode_bytes(e, &val, sizeof(uint32_t)); +} + +UPB_NOINLINE +static void encode_longvarint(upb_encstate* e, uint64_t val) { + size_t len; + char* start; + + encode_reserve(e, UPB_PB_VARINT_MAX_LEN); + len = encode_varint64(val, e->ptr); + start = e->ptr + UPB_PB_VARINT_MAX_LEN - len; + memmove(start, e->ptr, len); + e->ptr = start; +} + +UPB_FORCEINLINE +static void encode_varint(upb_encstate* e, uint64_t val) { + if (val < 128 && e->ptr != e->buf) { + --e->ptr; + *e->ptr = val; } else { - if (have) { - memcpy(e->ptr, data, have); - e->ptr += have; - } - e->overflow += (len - have); + encode_longvarint(e, val); } } -static void jsonenc_putstr(jsonenc* e, const char* str) { - jsonenc_putbytes(e, str, strlen(str)); +static void encode_double(upb_encstate* e, double d) { + uint64_t u64; + UPB_ASSERT(sizeof(double) == sizeof(uint64_t)); + memcpy(&u64, &d, sizeof(uint64_t)); + encode_fixed64(e, u64); } -UPB_PRINTF(2, 3) -static void jsonenc_printf(jsonenc* e, const char* fmt, ...) { - size_t n; - size_t have = e->end - e->ptr; - va_list args; +static void encode_float(upb_encstate* e, float d) { + uint32_t u32; + UPB_ASSERT(sizeof(float) == sizeof(uint32_t)); + memcpy(&u32, &d, sizeof(uint32_t)); + encode_fixed32(e, u32); +} - va_start(args, fmt); - n = vsnprintf(e->ptr, have, fmt, args); - va_end(args); +static void encode_tag(upb_encstate* e, uint32_t field_number, + uint8_t wire_type) { + encode_varint(e, (field_number << 3) | wire_type); +} - if (UPB_LIKELY(have > n)) { - e->ptr += n; +static void encode_fixedarray(upb_encstate* e, const upb_Array* arr, + size_t elem_size, uint32_t tag) { + size_t bytes = arr->size * elem_size; + const char* data = _upb_array_constptr(arr); + const char* ptr = data + bytes - elem_size; + + if (tag || !_upb_IsLittleEndian()) { + while (true) { + if (elem_size == 4) { + uint32_t val; + memcpy(&val, ptr, sizeof(val)); + val = _upb_BigEndian_Swap32(val); + encode_bytes(e, &val, elem_size); + } else { + UPB_ASSERT(elem_size == 8); + uint64_t val; + memcpy(&val, ptr, sizeof(val)); + val = _upb_BigEndian_Swap64(val); + encode_bytes(e, &val, elem_size); + } + + if (tag) encode_varint(e, tag); + if (ptr == data) break; + ptr -= elem_size; + } } else { - e->ptr = UPB_PTRADD(e->ptr, have); - e->overflow += (n - have); + encode_bytes(e, data, bytes); } } -static void jsonenc_nanos(jsonenc* e, int32_t nanos) { - int digits = 9; +static void encode_message(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable* m, size_t* size); - if (nanos == 0) return; - if (nanos < 0 || nanos >= 1000000000) { - jsonenc_err(e, "error formatting timestamp as JSON: invalid nanos"); - } +static void encode_scalar(upb_encstate* e, const void* _field_mem, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* f) { + const char* field_mem = _field_mem; + int wire_type; - while (nanos % 1000 == 0) { - nanos /= 1000; - digits -= 3; +#define CASE(ctype, type, wtype, encodeval) \ + { \ + ctype val = *(ctype*)field_mem; \ + encode_##type(e, encodeval); \ + wire_type = wtype; \ + break; \ } - jsonenc_printf(e, ".%.*" PRId32, digits, nanos); -} - -static void jsonenc_timestamp(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); - int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; - int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; - int L, N, I, J, K, hour, min, sec; - - if (seconds < -62135596800) { - jsonenc_err(e, - "error formatting timestamp as JSON: minimum acceptable value " - "is 0001-01-01T00:00:00Z"); - } else if (seconds > 253402300799) { - jsonenc_err(e, - "error formatting timestamp as JSON: maximum acceptable value " - "is 9999-12-31T23:59:59Z"); + switch (f->descriptortype) { + case kUpb_FieldType_Double: + CASE(double, double, kUpb_WireType_64Bit, val); + case kUpb_FieldType_Float: + CASE(float, float, kUpb_WireType_32Bit, val); + case kUpb_FieldType_Int64: + case kUpb_FieldType_UInt64: + CASE(uint64_t, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_UInt32: + CASE(uint32_t, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_Int32: + case kUpb_FieldType_Enum: + CASE(int32_t, varint, kUpb_WireType_Varint, (int64_t)val); + case kUpb_FieldType_SFixed64: + case kUpb_FieldType_Fixed64: + CASE(uint64_t, fixed64, kUpb_WireType_64Bit, val); + case kUpb_FieldType_Fixed32: + case kUpb_FieldType_SFixed32: + CASE(uint32_t, fixed32, kUpb_WireType_32Bit, val); + case kUpb_FieldType_Bool: + CASE(bool, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_SInt32: + CASE(int32_t, varint, kUpb_WireType_Varint, encode_zz32(val)); + case kUpb_FieldType_SInt64: + CASE(int64_t, varint, kUpb_WireType_Varint, encode_zz64(val)); + case kUpb_FieldType_String: + case kUpb_FieldType_Bytes: { + upb_StringView view = *(upb_StringView*)field_mem; + encode_bytes(e, view.data, view.size); + encode_varint(e, view.size); + wire_type = kUpb_WireType_Delimited; + break; + } + case kUpb_FieldType_Group: { + size_t size; + void* submsg = *(void**)field_mem; + const upb_MiniTable* subm = subs[f->submsg_index].submsg; + if (submsg == NULL) { + return; + } + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + encode_tag(e, f->number, kUpb_WireType_EndGroup); + encode_message(e, submsg, subm, &size); + wire_type = kUpb_WireType_StartGroup; + e->depth++; + break; + } + case kUpb_FieldType_Message: { + size_t size; + void* submsg = *(void**)field_mem; + const upb_MiniTable* subm = subs[f->submsg_index].submsg; + if (submsg == NULL) { + return; + } + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + encode_message(e, submsg, subm, &size); + encode_varint(e, size); + wire_type = kUpb_WireType_Delimited; + e->depth++; + break; + } + default: + UPB_UNREACHABLE(); } +#undef CASE - /* Julian Day -> Y/M/D, Algorithm from: - * Fliegel, H. F., and Van Flandern, T. C., "A Machine Algorithm for - * Processing Calendar Dates," Communications of the Association of - * Computing Machines, vol. 11 (1968), p. 657. */ - seconds += 62135596800; // Ensure seconds is positive. - L = (int)(seconds / 86400) - 719162 + 68569 + 2440588; - N = 4 * L / 146097; - L = L - (146097 * N + 3) / 4; - I = 4000 * (L + 1) / 1461001; - L = L - 1461 * I / 4 + 31; - J = 80 * L / 2447; - K = L - 2447 * J / 80; - L = J / 11; - J = J + 2 - 12 * L; - I = 100 * (N - 49) + I + L; - - sec = seconds % 60; - min = (seconds / 60) % 60; - hour = (seconds / 3600) % 24; - - jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec); - jsonenc_nanos(e, nanos); - jsonenc_putstr(e, "Z\""); + encode_tag(e, f->number, wire_type); } -static void jsonenc_duration(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); - int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; - int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; - - if (seconds > 315576000000 || seconds < -315576000000 || - (seconds < 0) != (nanos < 0)) { - jsonenc_err(e, "bad duration"); - } +static void encode_array(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* f) { + const upb_Array* arr = *UPB_PTR_AT(msg, f->offset, upb_Array*); + bool packed = f->mode & kUpb_LabelFlags_IsPacked; + size_t pre_len = e->limit - e->ptr; - if (nanos < 0) { - nanos = -nanos; + if (arr == NULL || arr->size == 0) { + return; } - jsonenc_printf(e, "\"%" PRId64, seconds); - jsonenc_nanos(e, nanos); - jsonenc_putstr(e, "s\""); -} - -static void jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) { - const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f); +#define VARINT_CASE(ctype, encode) \ + { \ + const ctype* start = _upb_array_constptr(arr); \ + const ctype* ptr = start + arr->size; \ + uint32_t tag = packed ? 0 : (f->number << 3) | kUpb_WireType_Varint; \ + do { \ + ptr--; \ + encode_varint(e, encode); \ + if (tag) encode_varint(e, tag); \ + } while (ptr != start); \ + } \ + break; - if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) { - jsonenc_putstr(e, "null"); - } else { - const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNumber(e_def, val); +#define TAG(wire_type) (packed ? 0 : (f->number << 3 | wire_type)) - if (ev) { - jsonenc_printf(e, "\"%s\"", upb_EnumValueDef_Name(ev)); - } else { - jsonenc_printf(e, "%" PRId32, val); + switch (f->descriptortype) { + case kUpb_FieldType_Double: + encode_fixedarray(e, arr, sizeof(double), TAG(kUpb_WireType_64Bit)); + break; + case kUpb_FieldType_Float: + encode_fixedarray(e, arr, sizeof(float), TAG(kUpb_WireType_32Bit)); + break; + case kUpb_FieldType_SFixed64: + case kUpb_FieldType_Fixed64: + encode_fixedarray(e, arr, sizeof(uint64_t), TAG(kUpb_WireType_64Bit)); + break; + case kUpb_FieldType_Fixed32: + case kUpb_FieldType_SFixed32: + encode_fixedarray(e, arr, sizeof(uint32_t), TAG(kUpb_WireType_32Bit)); + break; + case kUpb_FieldType_Int64: + case kUpb_FieldType_UInt64: + VARINT_CASE(uint64_t, *ptr); + case kUpb_FieldType_UInt32: + VARINT_CASE(uint32_t, *ptr); + case kUpb_FieldType_Int32: + case kUpb_FieldType_Enum: + VARINT_CASE(int32_t, (int64_t)*ptr); + case kUpb_FieldType_Bool: + VARINT_CASE(bool, *ptr); + case kUpb_FieldType_SInt32: + VARINT_CASE(int32_t, encode_zz32(*ptr)); + case kUpb_FieldType_SInt64: + VARINT_CASE(int64_t, encode_zz64(*ptr)); + case kUpb_FieldType_String: + case kUpb_FieldType_Bytes: { + const upb_StringView* start = _upb_array_constptr(arr); + const upb_StringView* ptr = start + arr->size; + do { + ptr--; + encode_bytes(e, ptr->data, ptr->size); + encode_varint(e, ptr->size); + encode_tag(e, f->number, kUpb_WireType_Delimited); + } while (ptr != start); + return; + } + case kUpb_FieldType_Group: { + const void* const* start = _upb_array_constptr(arr); + const void* const* ptr = start + arr->size; + const upb_MiniTable* subm = subs[f->submsg_index].submsg; + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + do { + size_t size; + ptr--; + encode_tag(e, f->number, kUpb_WireType_EndGroup); + encode_message(e, *ptr, subm, &size); + encode_tag(e, f->number, kUpb_WireType_StartGroup); + } while (ptr != start); + e->depth++; + return; + } + case kUpb_FieldType_Message: { + const void* const* start = _upb_array_constptr(arr); + const void* const* ptr = start + arr->size; + const upb_MiniTable* subm = subs[f->submsg_index].submsg; + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + do { + size_t size; + ptr--; + encode_message(e, *ptr, subm, &size); + encode_varint(e, size); + encode_tag(e, f->number, kUpb_WireType_Delimited); + } while (ptr != start); + e->depth++; + return; } } -} - -static void jsonenc_bytes(jsonenc* e, upb_StringView str) { - /* This is the regular base64, not the "web-safe" version. */ - static const char base64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - const unsigned char* ptr = (unsigned char*)str.data; - const unsigned char* end = UPB_PTRADD(ptr, str.size); - char buf[4]; - - jsonenc_putstr(e, "\""); - - while (end - ptr >= 3) { - buf[0] = base64[ptr[0] >> 2]; - buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; - buf[2] = base64[((ptr[1] & 0xf) << 2) | (ptr[2] >> 6)]; - buf[3] = base64[ptr[2] & 0x3f]; - jsonenc_putbytes(e, buf, 4); - ptr += 3; - } +#undef VARINT_CASE - switch (end - ptr) { - case 2: - buf[0] = base64[ptr[0] >> 2]; - buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; - buf[2] = base64[(ptr[1] & 0xf) << 2]; - buf[3] = '='; - jsonenc_putbytes(e, buf, 4); - break; - case 1: - buf[0] = base64[ptr[0] >> 2]; - buf[1] = base64[((ptr[0] & 0x3) << 4)]; - buf[2] = '='; - buf[3] = '='; - jsonenc_putbytes(e, buf, 4); - break; + if (packed) { + encode_varint(e, e->limit - e->ptr - pre_len); + encode_tag(e, f->number, kUpb_WireType_Delimited); } +} - jsonenc_putstr(e, "\""); +static void encode_mapentry(upb_encstate* e, uint32_t number, + const upb_MiniTable* layout, + const upb_MapEntry* ent) { + const upb_MiniTable_Field* key_field = &layout->fields[0]; + const upb_MiniTable_Field* val_field = &layout->fields[1]; + size_t pre_len = e->limit - e->ptr; + size_t size; + encode_scalar(e, &ent->v, layout->subs, val_field); + encode_scalar(e, &ent->k, layout->subs, key_field); + size = (e->limit - e->ptr) - pre_len; + encode_varint(e, size); + encode_tag(e, number, kUpb_WireType_Delimited); } -static void jsonenc_stringbody(jsonenc* e, upb_StringView str) { - const char* ptr = str.data; - const char* end = UPB_PTRADD(ptr, str.size); +static void encode_map(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* f) { + const upb_Map* map = *UPB_PTR_AT(msg, f->offset, const upb_Map*); + const upb_MiniTable* layout = subs[f->submsg_index].submsg; + UPB_ASSERT(layout->field_count == 2); - while (ptr < end) { - switch (*ptr) { - case '\n': - jsonenc_putstr(e, "\\n"); - break; - case '\r': - jsonenc_putstr(e, "\\r"); - break; - case '\t': - jsonenc_putstr(e, "\\t"); - break; - case '\"': - jsonenc_putstr(e, "\\\""); - break; - case '\f': - jsonenc_putstr(e, "\\f"); - break; - case '\b': - jsonenc_putstr(e, "\\b"); - break; - case '\\': - jsonenc_putstr(e, "\\\\"); - break; - default: - if ((uint8_t)*ptr < 0x20) { - jsonenc_printf(e, "\\u%04x", (int)(uint8_t)*ptr); - } else { - /* This could be a non-ASCII byte. We rely on the string being valid - * UTF-8. */ - jsonenc_putbytes(e, ptr, 1); - } - break; + if (map == NULL) return; + + if (e->options & kUpb_EncodeOption_Deterministic) { + _upb_sortedmap sorted; + _upb_mapsorter_pushmap(&e->sorter, layout->fields[0].descriptortype, map, + &sorted); + upb_MapEntry ent; + while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) { + encode_mapentry(e, f->number, layout, &ent); + } + _upb_mapsorter_popmap(&e->sorter, &sorted); + } else { + upb_strtable_iter i; + upb_strtable_begin(&i, &map->table); + for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { + upb_StringView key = upb_strtable_iter_key(&i); + const upb_value val = upb_strtable_iter_value(&i); + upb_MapEntry ent; + _upb_map_fromkey(key, &ent.k, map->key_size); + _upb_map_fromvalue(val, &ent.v, map->val_size); + encode_mapentry(e, f->number, layout, &ent); } - ptr++; } } -static void jsonenc_string(jsonenc* e, upb_StringView str) { - jsonenc_putstr(e, "\""); - jsonenc_stringbody(e, str); - jsonenc_putstr(e, "\""); -} - -static bool upb_JsonEncode_HandleSpecialDoubles(jsonenc* e, double val) { - if (val == INFINITY) { - jsonenc_putstr(e, "\"Infinity\""); - } else if (val == -INFINITY) { - jsonenc_putstr(e, "\"-Infinity\""); - } else if (val != val) { - jsonenc_putstr(e, "\"NaN\""); +static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* f) { + if (f->presence == 0) { + /* Proto3 presence or map/array. */ + const void* mem = UPB_PTR_AT(msg, f->offset, void); + switch (f->mode >> kUpb_FieldRep_Shift) { + case kUpb_FieldRep_1Byte: { + char ch; + memcpy(&ch, mem, 1); + return ch != 0; + } +#if UINTPTR_MAX == 0xffffffff + case kUpb_FieldRep_Pointer: +#endif + case kUpb_FieldRep_4Byte: { + uint32_t u32; + memcpy(&u32, mem, 4); + return u32 != 0; + } +#if UINTPTR_MAX != 0xffffffff + case kUpb_FieldRep_Pointer: +#endif + case kUpb_FieldRep_8Byte: { + uint64_t u64; + memcpy(&u64, mem, 8); + return u64 != 0; + } + case kUpb_FieldRep_StringView: { + const upb_StringView* str = (const upb_StringView*)mem; + return str->size != 0; + } + default: + UPB_UNREACHABLE(); + } + } else if (f->presence > 0) { + /* Proto2 presence: hasbit. */ + return _upb_hasbit_field(msg, f); } else { - return false; + /* Field is in a oneof. */ + return _upb_getoneofcase_field(msg, f) == f->number; } - return true; } -static void upb_JsonEncode_Double(jsonenc* e, double val) { - if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; - char buf[32]; - _upb_EncodeRoundTripDouble(val, buf, sizeof(buf)); - jsonenc_putstr(e, buf); -} - -static void upb_JsonEncode_Float(jsonenc* e, float val) { - if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; - char buf[32]; - _upb_EncodeRoundTripFloat(val, buf, sizeof(buf)); - jsonenc_putstr(e, buf); +static void encode_field(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field) { + switch (upb_FieldMode_Get(field)) { + case kUpb_FieldMode_Array: + encode_array(e, msg, subs, field); + break; + case kUpb_FieldMode_Map: + encode_map(e, msg, subs, field); + break; + case kUpb_FieldMode_Scalar: + encode_scalar(e, UPB_PTR_AT(msg, field->offset, void), subs, field); + break; + default: + UPB_UNREACHABLE(); + } } -static void jsonenc_wrapper(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(m, 1); - upb_MessageValue val = upb_Message_Get(msg, val_f); - jsonenc_scalar(e, val, val_f); +/* message MessageSet { + * repeated group Item = 1 { + * required int32 type_id = 2; + * required string message = 3; + * } + * } */ +static void encode_msgset_item(upb_encstate* e, + const upb_Message_Extension* ext) { + size_t size; + encode_tag(e, 1, kUpb_WireType_EndGroup); + encode_message(e, ext->data.ptr, ext->ext->sub.submsg, &size); + encode_varint(e, size); + encode_tag(e, 3, kUpb_WireType_Delimited); + encode_varint(e, ext->ext->field.number); + encode_tag(e, 2, kUpb_WireType_Varint); + encode_tag(e, 1, kUpb_WireType_StartGroup); } -static const upb_MessageDef* jsonenc_getanymsg(jsonenc* e, - upb_StringView type_url) { - /* Find last '/', if any. */ - const char* end = type_url.data + type_url.size; - const char* ptr = end; - const upb_MessageDef* ret; +static void encode_message(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable* m, size_t* size) { + size_t pre_len = e->limit - e->ptr; - if (!e->ext_pool) { - jsonenc_err(e, "Tried to encode Any, but no symtab was provided"); + if ((e->options & kUpb_EncodeOption_CheckRequired) && m->required_count) { + uint64_t msg_head; + memcpy(&msg_head, msg, 8); + msg_head = _upb_BigEndian_Swap64(msg_head); + if (upb_MiniTable_requiredmask(m) & ~msg_head) { + encode_err(e, kUpb_EncodeStatus_MissingRequired); + } } - if (type_url.size == 0) goto badurl; + if ((e->options & kUpb_EncodeOption_SkipUnknown) == 0) { + size_t unknown_size; + const char* unknown = upb_Message_GetUnknown(msg, &unknown_size); - while (true) { - if (--ptr == type_url.data) { - /* Type URL must contain at least one '/', with host before. */ - goto badurl; - } - if (*ptr == '/') { - ptr++; - break; + if (unknown) { + encode_bytes(e, unknown, unknown_size); } } - ret = upb_DefPool_FindMessageByNameWithSize(e->ext_pool, ptr, end - ptr); - - if (!ret) { - jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr); + if (m->ext != kUpb_ExtMode_NonExtendable) { + /* Encode all extensions together. Unlike C++, we do not attempt to keep + * these in field number order relative to normal fields or even to each + * other. */ + size_t ext_count; + const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &ext_count); + if (ext_count) { + const upb_Message_Extension* end = ext + ext_count; + for (; ext != end; ext++) { + if (UPB_UNLIKELY(m->ext == kUpb_ExtMode_IsMessageSet)) { + encode_msgset_item(e, ext); + } else { + encode_field(e, &ext->data, &ext->ext->sub, &ext->ext->field); + } + } + } } - return ret; + if (m->field_count) { + const upb_MiniTable_Field* f = &m->fields[m->field_count]; + const upb_MiniTable_Field* first = &m->fields[0]; + while (f != first) { + f--; + if (encode_shouldencode(e, msg, m->subs, f)) { + encode_field(e, msg, m->subs, f); + } + } + } -badurl: - jsonenc_errf(e, "Bad type URL: " UPB_STRINGVIEW_FORMAT, - UPB_STRINGVIEW_ARGS(type_url)); + *size = (e->limit - e->ptr) - pre_len; } -static void jsonenc_any(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); - upb_StringView type_url = upb_Message_Get(msg, type_url_f).str_val; - upb_StringView value = upb_Message_Get(msg, value_f).str_val; - const upb_MessageDef* any_m = jsonenc_getanymsg(e, type_url); - const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m); - upb_Arena* arena = jsonenc_arena(e); - upb_Message* any = upb_Message_New(any_m, arena); +upb_EncodeStatus upb_Encode(const void* msg, const upb_MiniTable* l, + int options, upb_Arena* arena, char** buf, + size_t* size) { + upb_encstate e; + unsigned depth = (unsigned)options >> 16; - if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) != - kUpb_DecodeStatus_Ok) { - jsonenc_err(e, "Error decoding message in Any"); - } + e.arena = arena; + e.buf = NULL; + e.limit = NULL; + e.ptr = NULL; + e.depth = depth ? depth : 64; + e.options = options; + _upb_mapsorter_init(&e.sorter); - jsonenc_putstr(e, "{\"@type\":"); - jsonenc_string(e, type_url); + upb_EncodeStatus status = UPB_SETJMP(e.err); - if (upb_MessageDef_WellKnownType(any_m) == kUpb_WellKnown_Unspecified) { - /* Regular messages: {"@type": "...","foo": 1, "bar": 2} */ - jsonenc_msgfields(e, any, any_m, false); + // Unfortunately we must continue to perform hackery here because there are + // code paths which blindly copy the returned pointer without bothering to + // check for errors until much later (b/235839510). So we still set *buf to + // NULL on error and we still set it to non-NULL on a successful empty result. + if (status == kUpb_EncodeStatus_Ok) { + encode_message(&e, msg, l, size); + *size = e.limit - e.ptr; + if (*size == 0) { + static char ch; + *buf = &ch; + } else { + UPB_ASSERT(e.ptr); + *buf = e.ptr; + } } else { - /* Well-known type: {"@type": "...","value": } */ - jsonenc_putstr(e, ",\"value\":"); - jsonenc_msgfield(e, any, any_m); + *buf = NULL; + *size = 0; } - jsonenc_putstr(e, "}"); + _upb_mapsorter_destroy(&e.sorter); + return status; } -static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) { - if (*first) { - *first = false; - } else { - jsonenc_putstr(e, str); - } + +// Must be last. + +static void _upb_mapsorter_getkeys(const void* _a, const void* _b, void* a_key, + void* b_key, size_t size) { + const upb_tabent* const* a = _a; + const upb_tabent* const* b = _b; + upb_StringView a_tabkey = upb_tabstrview((*a)->key); + upb_StringView b_tabkey = upb_tabstrview((*b)->key); + _upb_map_fromkey(a_tabkey, a_key, size); + _upb_map_fromkey(b_tabkey, b_key, size); } -static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) { - const char* ptr = path.data; - const char* end = ptr + path.size; +static int _upb_mapsorter_cmpi64(const void* _a, const void* _b) { + int64_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); + return a < b ? -1 : a > b; +} - while (ptr < end) { - char ch = *ptr; +static int _upb_mapsorter_cmpu64(const void* _a, const void* _b) { + uint64_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); + return a < b ? -1 : a > b; +} - if (ch >= 'A' && ch <= 'Z') { - jsonenc_err(e, "Field mask element may not have upper-case letter."); - } else if (ch == '_') { - if (ptr == end - 1 || *(ptr + 1) < 'a' || *(ptr + 1) > 'z') { - jsonenc_err(e, "Underscore must be followed by a lowercase letter."); - } - ch = *++ptr - 32; - } +static int _upb_mapsorter_cmpi32(const void* _a, const void* _b) { + int32_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); + return a < b ? -1 : a > b; +} + +static int _upb_mapsorter_cmpu32(const void* _a, const void* _b) { + uint32_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); + return a < b ? -1 : a > b; +} + +static int _upb_mapsorter_cmpbool(const void* _a, const void* _b) { + bool a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 1); + return a < b ? -1 : a > b; +} - jsonenc_putbytes(e, &ch, 1); - ptr++; - } +static int _upb_mapsorter_cmpstr(const void* _a, const void* _b) { + upb_StringView a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, UPB_MAPTYPE_STRING); + size_t common_size = UPB_MIN(a.size, b.size); + int cmp = memcmp(a.data, b.data, common_size); + if (cmp) return -cmp; + return a.size < b.size ? -1 : a.size > b.size; } -static void jsonenc_fieldmask(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_Array* paths = upb_Message_Get(msg, paths_f).array_val; - bool first = true; - size_t i, n = 0; +static int (*const compar[kUpb_FieldType_SizeOf])(const void*, const void*) = { + [kUpb_FieldType_Int64] = _upb_mapsorter_cmpi64, + [kUpb_FieldType_SFixed64] = _upb_mapsorter_cmpi64, + [kUpb_FieldType_SInt64] = _upb_mapsorter_cmpi64, - if (paths) n = upb_Array_Size(paths); + [kUpb_FieldType_UInt64] = _upb_mapsorter_cmpu64, + [kUpb_FieldType_Fixed64] = _upb_mapsorter_cmpu64, - jsonenc_putstr(e, "\""); + [kUpb_FieldType_Int32] = _upb_mapsorter_cmpi32, + [kUpb_FieldType_SInt32] = _upb_mapsorter_cmpi32, + [kUpb_FieldType_SFixed32] = _upb_mapsorter_cmpi32, + [kUpb_FieldType_Enum] = _upb_mapsorter_cmpi32, - for (i = 0; i < n; i++) { - jsonenc_putsep(e, ",", &first); - jsonenc_fieldpath(e, upb_Array_Get(paths, i).str_val); - } + [kUpb_FieldType_UInt32] = _upb_mapsorter_cmpu32, + [kUpb_FieldType_Fixed32] = _upb_mapsorter_cmpu32, - jsonenc_putstr(e, "\""); -} + [kUpb_FieldType_Bool] = _upb_mapsorter_cmpbool, -static void jsonenc_struct(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_Map* fields = upb_Message_Get(msg, fields_f).map_val; - const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); - size_t iter = kUpb_Map_Begin; - bool first = true; + [kUpb_FieldType_String] = _upb_mapsorter_cmpstr, + [kUpb_FieldType_Bytes] = _upb_mapsorter_cmpstr, +}; - jsonenc_putstr(e, "{"); +bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, + const upb_Map* map, _upb_sortedmap* sorted) { + int map_size = _upb_Map_Size(map); + sorted->start = s->size; + sorted->pos = sorted->start; + sorted->end = sorted->start + map_size; - if (fields) { - while (upb_MapIterator_Next(fields, &iter)) { - upb_MessageValue key = upb_MapIterator_Key(fields, iter); - upb_MessageValue val = upb_MapIterator_Value(fields, iter); + // Grow s->entries if necessary. + if (sorted->end > s->cap) { + s->cap = _upb_Log2CeilingSize(sorted->end); + s->entries = realloc(s->entries, s->cap * sizeof(*s->entries)); + if (!s->entries) return false; + } - jsonenc_putsep(e, ",", &first); - jsonenc_string(e, key.str_val); - jsonenc_putstr(e, ":"); - jsonenc_value(e, val.msg_val, upb_FieldDef_MessageSubDef(value_f)); + s->size = sorted->end; + + // Copy non-empty entries from the table to s->entries. + upb_tabent const** dst = &s->entries[sorted->start]; + const upb_tabent* src = map->table.t.entries; + const upb_tabent* end = src + upb_table_size(&map->table.t); + for (; src < end; src++) { + if (!upb_tabent_isempty(src)) { + *dst = src; + dst++; } } + UPB_ASSERT(dst == &s->entries[sorted->end]); - jsonenc_putstr(e, "}"); + // Sort entries according to the key type. + qsort(&s->entries[sorted->start], map_size, sizeof(*s->entries), + compar[key_type]); + return true; } -static void jsonenc_listvalue(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_MessageDef* values_m = upb_FieldDef_MessageSubDef(values_f); - const upb_Array* values = upb_Message_Get(msg, values_f).array_val; - size_t i; - bool first = true; - jsonenc_putstr(e, "["); +#include - if (values) { - const size_t size = upb_Array_Size(values); - for (i = 0; i < size; i++) { - upb_MessageValue elem = upb_Array_Get(values, i); - jsonenc_putsep(e, ",", &first); - jsonenc_value(e, elem.msg_val, values_m); - } - } +// Must be last. - jsonenc_putstr(e, "]"); +/** upb_Message ***************************************************************/ + +static const size_t overhead = sizeof(upb_Message_InternalData); + +static const upb_Message_Internal* upb_Message_Getinternal_const( + const upb_Message* msg) { + ptrdiff_t size = sizeof(upb_Message_Internal); + return (upb_Message_Internal*)((char*)msg - size); } -static void jsonenc_value(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - /* TODO(haberman): do we want a reflection method to get oneof case? */ - size_t iter = kUpb_Message_Begin; - const upb_FieldDef* f; - upb_MessageValue val; +upb_Message* _upb_Message_New(const upb_MiniTable* l, upb_Arena* a) { + return _upb_Message_New_inl(l, a); +} - if (!upb_Message_Next(msg, m, NULL, &f, &val, &iter)) { - jsonenc_err(e, "No value set in Value proto"); +void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l) { + void* mem = UPB_PTR_AT(msg, -sizeof(upb_Message_Internal), char); + memset(mem, 0, upb_msg_sizeof(l)); +} + +static bool realloc_internal(upb_Message* msg, size_t need, upb_Arena* arena) { + upb_Message_Internal* in = upb_Message_Getinternal(msg); + if (!in->internal) { + /* No internal data, allocate from scratch. */ + size_t size = UPB_MAX(128, _upb_Log2CeilingSize(need + overhead)); + upb_Message_InternalData* internal = upb_Arena_Malloc(arena, size); + if (!internal) return false; + internal->size = size; + internal->unknown_end = overhead; + internal->ext_begin = size; + in->internal = internal; + } else if (in->internal->ext_begin - in->internal->unknown_end < need) { + /* Internal data is too small, reallocate. */ + size_t new_size = _upb_Log2CeilingSize(in->internal->size + need); + size_t ext_bytes = in->internal->size - in->internal->ext_begin; + size_t new_ext_begin = new_size - ext_bytes; + upb_Message_InternalData* internal = + upb_Arena_Realloc(arena, in->internal, in->internal->size, new_size); + if (!internal) return false; + if (ext_bytes) { + /* Need to move extension data to the end. */ + char* ptr = (char*)internal; + memmove(ptr + new_ext_begin, ptr + internal->ext_begin, ext_bytes); + } + internal->ext_begin = new_ext_begin; + internal->size = new_size; + in->internal = internal; } + UPB_ASSERT(in->internal->ext_begin - in->internal->unknown_end >= need); + return true; +} - switch (upb_FieldDef_Number(f)) { - case 1: - jsonenc_putstr(e, "null"); - break; - case 2: - upb_JsonEncode_Double(e, val.double_val); - break; - case 3: - jsonenc_string(e, val.str_val); - break; - case 4: - jsonenc_putstr(e, val.bool_val ? "true" : "false"); - break; - case 5: - jsonenc_struct(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); - break; - case 6: - jsonenc_listvalue(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); - break; +bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, + upb_Arena* arena) { + if (!realloc_internal(msg, len, arena)) return false; + upb_Message_Internal* in = upb_Message_Getinternal(msg); + memcpy(UPB_PTR_AT(in->internal, in->internal->unknown_end, char), data, len); + in->internal->unknown_end += len; + return true; +} + +void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) { + upb_Message_Internal* in = upb_Message_Getinternal(msg); + if (in->internal) { + in->internal->unknown_end = overhead; } } -static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - switch (upb_MessageDef_WellKnownType(m)) { - case kUpb_WellKnown_Unspecified: - jsonenc_msg(e, msg, m); - break; - case kUpb_WellKnown_Any: - jsonenc_any(e, msg, m); - break; - case kUpb_WellKnown_FieldMask: - jsonenc_fieldmask(e, msg, m); - break; - case kUpb_WellKnown_Duration: - jsonenc_duration(e, msg, m); - break; - case kUpb_WellKnown_Timestamp: - jsonenc_timestamp(e, msg, m); - break; - case kUpb_WellKnown_DoubleValue: - case kUpb_WellKnown_FloatValue: - case kUpb_WellKnown_Int64Value: - case kUpb_WellKnown_UInt64Value: - case kUpb_WellKnown_Int32Value: - case kUpb_WellKnown_UInt32Value: - case kUpb_WellKnown_StringValue: - case kUpb_WellKnown_BytesValue: - case kUpb_WellKnown_BoolValue: - jsonenc_wrapper(e, msg, m); - break; - case kUpb_WellKnown_Value: - jsonenc_value(e, msg, m); - break; - case kUpb_WellKnown_ListValue: - jsonenc_listvalue(e, msg, m); - break; - case kUpb_WellKnown_Struct: - jsonenc_struct(e, msg, m); - break; +const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len) { + const upb_Message_Internal* in = upb_Message_Getinternal_const(msg); + if (in->internal) { + *len = in->internal->unknown_end - overhead; + return (char*)(in->internal + 1); + } else { + *len = 0; + return NULL; } } -static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, - const upb_FieldDef* f) { - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Bool: - jsonenc_putstr(e, val.bool_val ? "true" : "false"); - break; - case kUpb_CType_Float: - upb_JsonEncode_Float(e, val.float_val); - break; - case kUpb_CType_Double: - upb_JsonEncode_Double(e, val.double_val); - break; - case kUpb_CType_Int32: - jsonenc_printf(e, "%" PRId32, val.int32_val); - break; - case kUpb_CType_UInt32: - jsonenc_printf(e, "%" PRIu32, val.uint32_val); - break; - case kUpb_CType_Int64: - jsonenc_printf(e, "\"%" PRId64 "\"", val.int64_val); - break; - case kUpb_CType_UInt64: - jsonenc_printf(e, "\"%" PRIu64 "\"", val.uint64_val); - break; - case kUpb_CType_String: - jsonenc_string(e, val.str_val); - break; - case kUpb_CType_Bytes: - jsonenc_bytes(e, val.str_val); - break; - case kUpb_CType_Enum: - jsonenc_enum(val.int32_val, f, e); - break; - case kUpb_CType_Message: - jsonenc_msgfield(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); - break; +const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg, + size_t* count) { + const upb_Message_Internal* in = upb_Message_Getinternal_const(msg); + if (in->internal) { + *count = (in->internal->size - in->internal->ext_begin) / + sizeof(upb_Message_Extension); + return UPB_PTR_AT(in->internal, in->internal->ext_begin, void); + } else { + *count = 0; + return NULL; } } -static void jsonenc_mapkey(jsonenc* e, upb_MessageValue val, - const upb_FieldDef* f) { - jsonenc_putstr(e, "\""); +const upb_Message_Extension* _upb_Message_Getext( + const upb_Message* msg, const upb_MiniTable_Extension* e) { + size_t n; + const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &n); - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Bool: - jsonenc_putstr(e, val.bool_val ? "true" : "false"); - break; - case kUpb_CType_Int32: - jsonenc_printf(e, "%" PRId32, val.int32_val); - break; - case kUpb_CType_UInt32: - jsonenc_printf(e, "%" PRIu32, val.uint32_val); - break; - case kUpb_CType_Int64: - jsonenc_printf(e, "%" PRId64, val.int64_val); - break; - case kUpb_CType_UInt64: - jsonenc_printf(e, "%" PRIu64, val.uint64_val); - break; - case kUpb_CType_String: - jsonenc_stringbody(e, val.str_val); - break; - default: - UPB_UNREACHABLE(); + /* For now we use linear search exclusively to find extensions. If this + * becomes an issue due to messages with lots of extensions, we can introduce + * a table of some sort. */ + for (size_t i = 0; i < n; i++) { + if (ext[i].ext == e) { + return &ext[i]; + } } - jsonenc_putstr(e, "\":"); + return NULL; } -static void jsonenc_array(jsonenc* e, const upb_Array* arr, - const upb_FieldDef* f) { - size_t i; - size_t size = arr ? upb_Array_Size(arr) : 0; - bool first = true; - - jsonenc_putstr(e, "["); - - for (i = 0; i < size; i++) { - jsonenc_putsep(e, ",", &first); - jsonenc_scalar(e, upb_Array_Get(arr, i), f); +void _upb_Message_Clearext(upb_Message* msg, + const upb_MiniTable_Extension* ext_l) { + upb_Message_Internal* in = upb_Message_Getinternal(msg); + if (!in->internal) return; + const upb_Message_Extension* base = + UPB_PTR_AT(in->internal, in->internal->ext_begin, void); + upb_Message_Extension* ext = + (upb_Message_Extension*)_upb_Message_Getext(msg, ext_l); + if (ext) { + *ext = *base; + in->internal->ext_begin += sizeof(upb_Message_Extension); } +} - jsonenc_putstr(e, "]"); +upb_Message_Extension* _upb_Message_GetOrCreateExtension( + upb_Message* msg, const upb_MiniTable_Extension* e, upb_Arena* arena) { + upb_Message_Extension* ext = + (upb_Message_Extension*)_upb_Message_Getext(msg, e); + if (ext) return ext; + if (!realloc_internal(msg, sizeof(upb_Message_Extension), arena)) return NULL; + upb_Message_Internal* in = upb_Message_Getinternal(msg); + in->internal->ext_begin -= sizeof(upb_Message_Extension); + ext = UPB_PTR_AT(in->internal, in->internal->ext_begin, void); + memset(ext, 0, sizeof(upb_Message_Extension)); + ext->ext = e; + return ext; } -static void jsonenc_map(jsonenc* e, const upb_Map* map, const upb_FieldDef* f) { - const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); - const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); - const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); - size_t iter = kUpb_Map_Begin; - bool first = true; +size_t upb_Message_ExtensionCount(const upb_Message* msg) { + size_t count; + _upb_Message_Getexts(msg, &count); + return count; +} - jsonenc_putstr(e, "{"); +/** upb_Map *******************************************************************/ - if (map) { - while (upb_MapIterator_Next(map, &iter)) { - jsonenc_putsep(e, ",", &first); - jsonenc_mapkey(e, upb_MapIterator_Key(map, iter), key_f); - jsonenc_scalar(e, upb_MapIterator_Value(map, iter), val_f); - } +upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size) { + upb_Map* map = upb_Arena_Malloc(a, sizeof(upb_Map)); + + if (!map) { + return NULL; } - jsonenc_putstr(e, "}"); + upb_strtable_init(&map->table, 4, a); + map->key_size = key_size; + map->val_size = value_size; + + return map; } -static void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f, - upb_MessageValue val, bool* first) { - const char* name; +const float kUpb_FltInfinity = INFINITY; +const double kUpb_Infinity = INFINITY; - jsonenc_putsep(e, ",", first); - if (upb_FieldDef_IsExtension(f)) { - // TODO: For MessageSet, I would have expected this to print the message - // name here, but Python doesn't appear to do this. We should do more - // research here about what various implementations do. - jsonenc_printf(e, "\"[%s]\":", upb_FieldDef_FullName(f)); - } else { - if (e->options & upb_JsonEncode_UseProtoNames) { - name = upb_FieldDef_Name(f); - } else { - name = upb_FieldDef_JsonName(f); - } - jsonenc_printf(e, "\"%s\":", name); - } +#include +#include +#include +#include +#include +#include - if (upb_FieldDef_IsMap(f)) { - jsonenc_map(e, val.map_val, f); - } else if (upb_FieldDef_IsRepeated(f)) { - jsonenc_array(e, val.array_val, f); - } else { - jsonenc_scalar(e, val, f); - } +// Must be last. + +void upb_Status_Clear(upb_Status* status) { + if (!status) return; + status->ok = true; + status->msg[0] = '\0'; } -static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m, bool first) { - upb_MessageValue val; - const upb_FieldDef* f; +bool upb_Status_IsOk(const upb_Status* status) { return status->ok; } - if (e->options & upb_JsonEncode_EmitDefaults) { - /* Iterate over all fields. */ - int i = 0; - int n = upb_MessageDef_FieldCount(m); - for (i = 0; i < n; i++) { - f = upb_MessageDef_Field(m, i); - if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) { - jsonenc_fieldval(e, f, upb_Message_Get(msg, f), &first); - } - } - } else { - /* Iterate over non-empty fields. */ - size_t iter = kUpb_Message_Begin; - while (upb_Message_Next(msg, m, e->ext_pool, &f, &val, &iter)) { - jsonenc_fieldval(e, f, val, &first); - } - } +const char* upb_Status_ErrorMessage(const upb_Status* status) { + return status->msg; } -static void jsonenc_msg(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - jsonenc_putstr(e, "{"); - jsonenc_msgfields(e, msg, m, true); - jsonenc_putstr(e, "}"); +void upb_Status_SetErrorMessage(upb_Status* status, const char* msg) { + if (!status) return; + status->ok = false; + strncpy(status->msg, msg, _kUpb_Status_MaxMessage - 1); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; } -static size_t jsonenc_nullz(jsonenc* e, size_t size) { - size_t ret = e->ptr - e->buf + e->overflow; +void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + upb_Status_VSetErrorFormat(status, fmt, args); + va_end(args); +} - if (size > 0) { - if (e->ptr == e->end) e->ptr--; - *e->ptr = '\0'; - } +void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, + va_list args) { + if (!status) return; + status->ok = false; + vsnprintf(status->msg, sizeof(status->msg), fmt, args); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; +} - return ret; +void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, + va_list args) { + size_t len; + if (!status) return; + status->ok = false; + len = strlen(status->msg); + vsnprintf(status->msg + len, sizeof(status->msg) - len, fmt, args); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; } -size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, - const upb_DefPool* ext_pool, int options, char* buf, - size_t size, upb_Status* status) { - jsonenc e; +#include +#include +#include - e.buf = buf; - e.ptr = buf; - e.end = UPB_PTRADD(buf, size); - e.overflow = 0; - e.options = options; - e.ext_pool = ext_pool; - e.status = status; - e.arena = NULL; - if (setjmp(e.err)) return -1; +// Must be last. - jsonenc_msgfield(&e, msg, m); - if (e.arena) upb_Arena_Free(e.arena); - return jsonenc_nullz(&e, size); +/* Miscellaneous utilities ****************************************************/ + +static void upb_FixLocale(char* p) { + /* printf() is dependent on locales; sadly there is no easy and portable way + * to avoid this. This little post-processing step will translate 1,2 -> 1.2 + * since JSON needs the latter. Arguably a hack, but it is simple and the + * alternatives are far more complicated, platform-dependent, and/or larger + * in code size. */ + for (; *p; p++) { + if (*p == ',') *p = '.'; + } +} + +void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size) { + assert(size >= kUpb_RoundTripBufferSize); + snprintf(buf, size, "%.*g", DBL_DIG, val); + if (strtod(buf, NULL) != val) { + snprintf(buf, size, "%.*g", DBL_DIG + 2, val); + assert(strtod(buf, NULL) == val); + } + upb_FixLocale(buf); +} + +void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size) { + assert(size >= kUpb_RoundTripBufferSize); + snprintf(buf, size, "%.*g", FLT_DIG, val); + if (strtof(buf, NULL) != val) { + snprintf(buf, size, "%.*g", FLT_DIG + 3, val); + assert(strtof(buf, NULL) == val); + } + upb_FixLocale(buf); } -/** upb/port_undef.inc ************************************************************/ /* See port_def.inc. This should #undef all macros #defined there. */ #undef UPB_SIZE @@ -11380,6 +12974,7 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #undef UPB_ALIGN_DOWN #undef UPB_ALIGN_MALLOC #undef UPB_ALIGN_OF +#undef UPB_MALLOC_ALIGN #undef UPB_LIKELY #undef UPB_UNLIKELY #undef UPB_FORCEINLINE @@ -11402,3 +12997,6 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #undef UPB_POISON_MEMORY_REGION #undef UPB_UNPOISON_MEMORY_REGION #undef UPB_ASAN +#undef UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 +#undef UPB_DEPRECATED +#undef UPB_GNUC_MIN diff --git a/php/ext/google/protobuf/php-upb.h b/php/ext/google/protobuf/php-upb.h index 5af4e27dfc..42874797c6 100644 --- a/php/ext/google/protobuf/php-upb.h +++ b/php/ext/google/protobuf/php-upb.h @@ -1,30 +1,4 @@ /* Amalgamated source file */ -/* - * Copyright (c) 2009-2021, Google LLC - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Google LLC nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ /* * This is where we define macros used across upb. @@ -55,8 +29,20 @@ #error upb requires C99 or C++11 or MSVC >= 2015. #endif -#include +// Portable check for GCC minimum version: +// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +#define UPB_GNUC_MIN(x, y) \ + (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y)) +#else +#define UPB_GNUC_MIN(x, y) 0 +#endif + +#include +#include +#include #include +#include #if UINTPTR_MAX == 0xffffffff #define UPB_SIZE(size32, size64) size32 @@ -89,9 +75,10 @@ #define UPB_INLINE static #endif +#define UPB_MALLOC_ALIGN 8 #define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align)) #define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align)) -#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, 16) +#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, UPB_MALLOC_ALIGN) #define UPB_ALIGN_OF(type) offsetof (struct { char c; type member; }, member) /* Hints to the compiler about likely/unlikely branches. */ @@ -229,7 +216,11 @@ #undef UPB_FASTTABLE_SUPPORTED -/* ASAN poisoning (for arena) *************************************************/ +/* ASAN poisoning (for arena). + * If using UPB from an interpreted language like Ruby, a build of the + * interpreter compiled with ASAN enabled must be used in order to get sane and + * expected behavior. + */ #if defined(__SANITIZE_ADDRESS__) #define UPB_ASAN 1 @@ -253,16 +244,43 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); ((void)(addr), (void)(size)) #endif -/** upb/decode.h ************************************************************/ -/* - * upb_decode: parsing into a upb_Message using a upb_MiniTable. - */ +/* Disable proto2 arena behavior (TEMPORARY) **********************************/ -#ifndef UPB_DECODE_H_ -#define UPB_DECODE_H_ +#ifdef UPB_DISABLE_PROTO2_ENUM_CHECKING +#define UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 1 +#else +#define UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 0 +#endif + +#if defined(__cplusplus) +#if defined(__clang__) || UPB_GNUC_MIN(6, 0) +// https://gcc.gnu.org/gcc-6/changes.html +#if __cplusplus >= 201402L +#define UPB_DEPRECATED [[deprecated]] +#else +#define UPB_DEPRECATED __attribute__((deprecated)) +#endif +#else +#define UPB_DEPRECATED +#endif +#else +#define UPB_DEPRECATED +#endif + +#ifndef UPB_INTERNAL_ARRAY_H_ +#define UPB_INTERNAL_ARRAY_H_ + +#include + + +#ifndef UPB_ARRAY_H_ +#define UPB_ARRAY_H_ + + +#ifndef UPB_MESSAGE_VALUE_H_ +#define UPB_MESSAGE_VALUE_H_ -/** upb/msg.h ************************************************************/ /* * Public APIs for message operations that do not require descriptors. * These functions can be used even in build that does not want to depend on @@ -274,97 +292,37 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); #ifndef UPB_MSG_H_ #define UPB_MSG_H_ -#include +#ifndef UPB_ARENA_H_ +#define UPB_ARENA_H_ -/** upb/upb.h ************************************************************/ -/* - * This file contains shared definitions that are widely used across upb. - */ +#include -#ifndef UPB_H_ -#define UPB_H_ -#include -#include -#include -#include -#include -#include +#ifndef UPB_ALLOC_H_ +#define UPB_ALLOC_H_ +// Must be last. #ifdef __cplusplus extern "C" { #endif -/* upb_Status *****************************************************************/ - -#define _kUpb_Status_MaxMessage 127 - -typedef struct { - bool ok; - char msg[_kUpb_Status_MaxMessage]; /* Error message; NULL-terminated. */ -} upb_Status; - -const char* upb_Status_ErrorMessage(const upb_Status* status); -bool upb_Status_IsOk(const upb_Status* status); - -/* These are no-op if |status| is NULL. */ -void upb_Status_Clear(upb_Status* status); -void upb_Status_SetErrorMessage(upb_Status* status, const char* msg); -void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) - UPB_PRINTF(2, 3); -void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, - va_list args) UPB_PRINTF(2, 0); -void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, - va_list args) UPB_PRINTF(2, 0); - -/** upb_StringView ************************************************************/ - -typedef struct { - const char* data; - size_t size; -} upb_StringView; - -UPB_INLINE upb_StringView upb_StringView_FromDataAndSize(const char* data, - size_t size) { - upb_StringView ret; - ret.data = data; - ret.size = size; - return ret; -} - -UPB_INLINE upb_StringView upb_StringView_FromString(const char* data) { - return upb_StringView_FromDataAndSize(data, strlen(data)); -} - -UPB_INLINE bool upb_StringView_IsEqual(upb_StringView a, upb_StringView b) { - return a.size == b.size && memcmp(a.data, b.data, a.size) == 0; -} - -#define UPB_STRINGVIEW_INIT(ptr, len) \ - { ptr, len } - -#define UPB_STRINGVIEW_FORMAT "%.*s" -#define UPB_STRINGVIEW_ARGS(view) (int)(view).size, (view).data - -/** upb_alloc *****************************************************************/ - -/* A upb_alloc is a possibly-stateful allocator object. - * - * It could either be an arena allocator (which doesn't require individual - * free() calls) or a regular malloc() (which does). The client must therefore - * free memory unless it knows that the allocator is an arena allocator. */ - -struct upb_alloc; typedef struct upb_alloc upb_alloc; -/* A malloc()/free() function. - * If "size" is 0 then the function acts like free(), otherwise it acts like - * realloc(). Only "oldsize" bytes from a previous allocation are preserved. */ +/* A combined `malloc()`/`free()` function. + * If `size` is 0 then the function acts like `free()`, otherwise it acts like + * `realloc()`. Only `oldsize` bytes from a previous allocation are + * preserved. */ typedef void* upb_alloc_func(upb_alloc* alloc, void* ptr, size_t oldsize, size_t size); +/* A upb_alloc is a possibly-stateful allocator object. + * + * It could either be an arena allocator (which doesn't require individual + * `free()` calls) or a regular `malloc()` (which does). The client must + * therefore free memory unless it knows that the allocator is an arena + * allocator. */ struct upb_alloc { upb_alloc_func* func; }; @@ -381,7 +339,7 @@ UPB_INLINE void* upb_realloc(upb_alloc* alloc, void* ptr, size_t oldsize, } UPB_INLINE void upb_free(upb_alloc* alloc, void* ptr) { - assert(alloc); + UPB_ASSERT(alloc); alloc->func(alloc, ptr, 0, 0); } @@ -404,7 +362,18 @@ UPB_INLINE void* upb_grealloc(void* ptr, size_t oldsize, size_t size) { UPB_INLINE void upb_gfree(void* ptr) { upb_free(&upb_alloc_global, ptr); } -/* upb_Arena ******************************************************************/ +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_ALLOC_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif /* upb_Arena is a specific allocator implementation that uses arena allocation. * The user provides an allocator that will be used to allocate the underlying @@ -420,7 +389,6 @@ UPB_INLINE void upb_gfree(void* ptr) { upb_free(&upb_alloc_global, ptr); } typedef void upb_CleanupFunc(void* ud); -struct upb_Arena; typedef struct upb_Arena upb_Arena; typedef struct { @@ -440,6 +408,8 @@ void upb_Arena_Free(upb_Arena* a); bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func); bool upb_Arena_Fuse(upb_Arena* a, upb_Arena* b); void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size); +size_t upb_Arena_SpaceAllocated(upb_Arena* arena); +uint32_t upb_Arena_DebugRefCount(upb_Arena* arena); UPB_INLINE upb_alloc* upb_Arena_Alloc(upb_Arena* a) { return (upb_alloc*)a; } @@ -448,18 +418,14 @@ UPB_INLINE size_t _upb_ArenaHas(upb_Arena* a) { return (size_t)(h->end - h->ptr); } -UPB_INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) { +UPB_INLINE void* _upb_Arena_FastMalloc(upb_Arena* a, size_t size) { _upb_ArenaHead* h = (_upb_ArenaHead*)a; - void* ret; - size = UPB_ALIGN_MALLOC(size); - - if (UPB_UNLIKELY(_upb_ArenaHas(a) < size)) { - return _upb_Arena_SlowMalloc(a, size); - } + void* ret = h->ptr; + UPB_ASSERT(UPB_ALIGN_MALLOC((uintptr_t)ret) == (uintptr_t)ret); + UPB_ASSERT(UPB_ALIGN_MALLOC(size) == size); + UPB_UNPOISON_MEMORY_REGION(ret, size); - ret = h->ptr; h->ptr += size; - UPB_UNPOISON_MEMORY_REGION(ret, size); #if UPB_ASAN { @@ -475,136 +441,77 @@ UPB_INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) { return ret; } -UPB_INLINE void* upb_Arena_Realloc(upb_Arena* a, void* ptr, size_t oldsize, - size_t size) { - void* ret = upb_Arena_Malloc(a, size); +UPB_INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) { + size = UPB_ALIGN_MALLOC(size); - if (ret && oldsize > 0) { - memcpy(ret, ptr, oldsize); + if (UPB_UNLIKELY(_upb_ArenaHas(a) < size)) { + return _upb_Arena_SlowMalloc(a, size); } - return ret; + return _upb_Arena_FastMalloc(a, size); } -UPB_INLINE upb_Arena* upb_Arena_New(void) { - return upb_Arena_Init(NULL, 0, &upb_alloc_global); +// Shrinks the last alloc from arena. +// REQUIRES: (ptr, oldsize) was the last malloc/realloc from this arena. +// We could also add a upb_Arena_TryShrinkLast() which is simply a no-op if +// this was not the last alloc. +UPB_INLINE void upb_Arena_ShrinkLast(upb_Arena* a, void* ptr, size_t oldsize, + size_t size) { + _upb_ArenaHead* h = (_upb_ArenaHead*)a; + oldsize = UPB_ALIGN_MALLOC(oldsize); + size = UPB_ALIGN_MALLOC(size); + UPB_ASSERT((char*)ptr + oldsize == h->ptr); // Must be the last alloc. + UPB_ASSERT(size <= oldsize); + h->ptr = (char*)ptr + size; } -/* Constants ******************************************************************/ - -/* A list of types as they are encoded on-the-wire. */ -typedef enum { - kUpb_WireType_Varint = 0, - kUpb_WireType_64Bit = 1, - kUpb_WireType_Delimited = 2, - kUpb_WireType_StartGroup = 3, - kUpb_WireType_EndGroup = 4, - kUpb_WireType_32Bit = 5 -} upb_WireType; - -/* The types a field can have. Note that this list is not identical to the - * types defined in descriptor.proto, which gives INT32 and SINT32 separate - * types (we distinguish the two with the "integer encoding" enum below). */ -typedef enum { - kUpb_CType_Bool = 1, - kUpb_CType_Float = 2, - kUpb_CType_Int32 = 3, - kUpb_CType_UInt32 = 4, - kUpb_CType_Enum = 5, /* Enum values are int32. */ - kUpb_CType_Message = 6, - kUpb_CType_Double = 7, - kUpb_CType_Int64 = 8, - kUpb_CType_UInt64 = 9, - kUpb_CType_String = 10, - kUpb_CType_Bytes = 11 -} upb_CType; - -/* The repeated-ness of each field; this matches descriptor.proto. */ -typedef enum { - kUpb_Label_Optional = 1, - kUpb_Label_Required = 2, - kUpb_Label_Repeated = 3 -} upb_Label; - -/* Descriptor types, as defined in descriptor.proto. */ -typedef enum { - kUpb_FieldType_Double = 1, - kUpb_FieldType_Float = 2, - kUpb_FieldType_Int64 = 3, - kUpb_FieldType_UInt64 = 4, - kUpb_FieldType_Int32 = 5, - kUpb_FieldType_Fixed64 = 6, - kUpb_FieldType_Fixed32 = 7, - kUpb_FieldType_Bool = 8, - kUpb_FieldType_String = 9, - kUpb_FieldType_Group = 10, - kUpb_FieldType_Message = 11, - kUpb_FieldType_Bytes = 12, - kUpb_FieldType_UInt32 = 13, - kUpb_FieldType_Enum = 14, - kUpb_FieldType_SFixed32 = 15, - kUpb_FieldType_SFixed64 = 16, - kUpb_FieldType_SInt32 = 17, - kUpb_FieldType_SInt64 = 18 -} upb_FieldType; +UPB_INLINE void* upb_Arena_Realloc(upb_Arena* a, void* ptr, size_t oldsize, + size_t size) { + _upb_ArenaHead* h = (_upb_ArenaHead*)a; + oldsize = UPB_ALIGN_MALLOC(oldsize); + size = UPB_ALIGN_MALLOC(size); + bool is_most_recent_alloc = (uintptr_t)ptr + oldsize == (uintptr_t)h->ptr; -#define kUpb_Map_Begin ((size_t)-1) + if (is_most_recent_alloc) { + ptrdiff_t diff = size - oldsize; + if ((ptrdiff_t)_upb_ArenaHas(a) >= diff) { + h->ptr += diff; + return ptr; + } + } else if (size <= oldsize) { + return ptr; + } -UPB_INLINE bool _upb_IsLittleEndian(void) { - int x = 1; - return *(char*)&x == 1; -} + void* ret = upb_Arena_Malloc(a, size); -UPB_INLINE uint32_t _upb_BigEndian_Swap32(uint32_t val) { - if (_upb_IsLittleEndian()) { - return val; - } else { - return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | - ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24); + if (ret && oldsize > 0) { + memcpy(ret, ptr, UPB_MIN(oldsize, size)); } -} -UPB_INLINE uint64_t _upb_BigEndian_Swap64(uint64_t val) { - if (_upb_IsLittleEndian()) { - return val; - } else { - return ((uint64_t)_upb_BigEndian_Swap32(val) << 32) | - _upb_BigEndian_Swap32(val >> 32); - } + return ret; } -UPB_INLINE int _upb_Log2Ceiling(int x) { - if (x <= 1) return 0; -#ifdef __GNUC__ - return 32 - __builtin_clz(x - 1); -#else - int lg2 = 0; - while (1 << lg2 < x) lg2++; - return lg2; -#endif +UPB_INLINE upb_Arena* upb_Arena_New(void) { + return upb_Arena_Init(NULL, 0, &upb_alloc_global); } -UPB_INLINE int _upb_Log2Ceilingsize(int x) { return 1 << _upb_Log2Ceiling(x); } - - #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_H_ */ + +#endif /* UPB_ARENA_H_ */ + +// Must be last. #ifdef __cplusplus extern "C" { #endif -/** upb_Message - * *******************************************************************/ - typedef void upb_Message; /* For users these are opaque. They can be obtained from * upb_MessageDef_MiniTable() but users cannot access any of the members. */ -struct upb_MiniTable; typedef struct upb_MiniTable upb_MiniTable; /* Adds unknown data (serialized protobuf data) to the given message. The data @@ -618,167 +525,78 @@ const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len); /* Returns the number of extensions present in this message. */ size_t upb_Message_ExtensionCount(const upb_Message* msg); -/** upb_ExtensionRegistry *****************************************************/ +#ifdef __cplusplus +} /* extern "C" */ +#endif -/* Extension registry: a dynamic data structure that stores a map of: - * (upb_MiniTable, number) -> extension info - * - * upb_decode() uses upb_ExtensionRegistry to look up extensions while parsing - * binary format. - * - * upb_ExtensionRegistry is part of the mini-table (msglayout) family of - * objects. Like all mini-table objects, it is suitable for reflection-less - * builds that do not want to expose names into the binary. - * - * Unlike most mini-table types, upb_ExtensionRegistry requires dynamic memory - * allocation and dynamic initialization: - * * If reflection is being used, then upb_DefPool will construct an appropriate - * upb_ExtensionRegistry automatically. - * * For a mini-table only build, the user must manually construct the - * upb_ExtensionRegistry and populate it with all of the extensions the user - * cares about. - * * A third alternative is to manually unpack relevant extensions after the - * main parse is complete, similar to how Any works. This is perhaps the - * nicest solution from the perspective of reducing dependencies, avoiding - * dynamic memory allocation, and avoiding the need to parse uninteresting - * extensions. The downsides are: - * (1) parse errors are not caught during the main parse - * (2) the CPU hit of parsing comes during access, which could cause an - * undesirable stutter in application performance. - * - * Users cannot directly get or put into this map. Users can only add the - * extensions from a generated module and pass the extension registry to the - * binary decoder. - * - * A upb_DefPool provides a upb_ExtensionRegistry, so any users who use - * reflection do not need to populate a upb_ExtensionRegistry directly. - */ -struct upb_ExtensionRegistry; -typedef struct upb_ExtensionRegistry upb_ExtensionRegistry; - -/* Creates a upb_ExtensionRegistry in the given arena. The arena must outlive - * any use of the extreg. */ -upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena); +#endif /* UPB_MSG_INT_H_ */ -#ifdef __cplusplus -} /* extern "C" */ -#endif +#ifndef UPB_STRING_VIEW_H_ +#define UPB_STRING_VIEW_H_ -#endif /* UPB_MSG_INT_H_ */ +#include -/* Must be last. */ +// Must be last. #ifdef __cplusplus extern "C" { #endif -enum { - /* If set, strings will alias the input buffer instead of copying into the - * arena. */ - kUpb_DecodeOption_AliasString = 1, +typedef struct { + const char* data; + size_t size; +} upb_StringView; - /* If set, the parse will return failure if any message is missing any - * required fields when the message data ends. The parse will still continue, - * and the failure will only be reported at the end. - * - * IMPORTANT CAVEATS: - * - * 1. This can throw a false positive failure if an incomplete message is seen - * on the wire but is later completed when the sub-message occurs again. - * For this reason, a second pass is required to verify a failure, to be - * truly robust. - * - * 2. This can return a false success if you are decoding into a message that - * already has some sub-message fields present. If the sub-message does - * not occur in the binary payload, we will never visit it and discover the - * incomplete sub-message. For this reason, this check is only useful for - * implemting ParseFromString() semantics. For MergeFromString(), a - * post-parse validation step will always be necessary. */ - kUpb_DecodeOption_CheckRequired = 2, -}; +UPB_INLINE upb_StringView upb_StringView_FromDataAndSize(const char* data, + size_t size) { + upb_StringView ret; + ret.data = data; + ret.size = size; + return ret; +} -#define UPB_DECODE_MAXDEPTH(depth) ((depth) << 16) +UPB_INLINE upb_StringView upb_StringView_FromString(const char* data) { + return upb_StringView_FromDataAndSize(data, strlen(data)); +} -typedef enum { - kUpb_DecodeStatus_Ok = 0, - kUpb_DecodeStatus_Malformed = 1, // Wire format was corrupt - kUpb_DecodeStatus_OutOfMemory = 2, // Arena alloc failed - kUpb_DecodeStatus_BadUtf8 = 3, // String field had bad UTF-8 - kUpb_DecodeStatus_MaxDepthExceeded = 4, // Exceeded UPB_DECODE_MAXDEPTH +UPB_INLINE bool upb_StringView_IsEqual(upb_StringView a, upb_StringView b) { + return a.size == b.size && memcmp(a.data, b.data, a.size) == 0; +} - // kUpb_DecodeOption_CheckRequired failed (see above), but the parse otherwise - // succeeded. - kUpb_DecodeStatus_MissingRequired = 5, -} upb_DecodeStatus; +#define UPB_STRINGVIEW_INIT(ptr, len) \ + { ptr, len } -upb_DecodeStatus upb_Decode(const char* buf, size_t size, upb_Message* msg, - const upb_MiniTable* l, - const upb_ExtensionRegistry* extreg, int options, - upb_Arena* arena); +#define UPB_STRINGVIEW_FORMAT "%.*s" +#define UPB_STRINGVIEW_ARGS(view) (int)(view).size, (view).data #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_DECODE_H_ */ +#endif /* UPB_STRING_VIEW_H_ */ -/** upb/decode_internal.h ************************************************************/ /* - * Internal implementation details of the decoder that are shared between - * decode.c and decode_fast.c. + * This file contains shared definitions that are widely used across upb. */ -#ifndef UPB_DECODE_INT_H_ -#define UPB_DECODE_INT_H_ - -#include - -#include "third_party/utf8_range/utf8_range.h" - -/** upb/msg_internal.h ************************************************************/ -/* -** Our memory representation for parsing tables and messages themselves. -** Functions in this file are used by generated code and possibly reflection. -** -** The definitions in this file are internal to upb. -**/ - -#ifndef UPB_MSG_INT_H_ -#define UPB_MSG_INT_H_ +#ifndef UPB_H_ +#define UPB_H_ +#include +#include +#include +#include #include -#include #include +// TODO(b/232091617): Remove these and fix everything that breaks as a result. -/** upb/table_internal.h ************************************************************/ -/* - * upb_table - * - * This header is INTERNAL-ONLY! Its interfaces are not public or stable! - * This file defines very fast int->upb_value (inttable) and string->upb_value - * (strtable) hash tables. - * - * The table uses chained scatter with Brent's variation (inspired by the Lua - * implementation of hash tables). The hash function for strings is Austin - * Appleby's "MurmurHash." - * - * The inttable uses uintptr_t as its key, which guarantees it can be used to - * store pointers or integers of at least 32 bits (upb isn't really useful on - * systems where sizeof(void*) < 4). - * - * The table must be homogeneous (all values of the same type). In debug - * mode, we check this on insert and lookup. - */ - -#ifndef UPB_TABLE_H_ -#define UPB_TABLE_H_ - -#include -#include +#ifndef UPB_STATUS_H_ +#define UPB_STATUS_H_ +#include // Must be last. @@ -786,1493 +604,1570 @@ upb_DecodeStatus upb_Decode(const char* buf, size_t size, upb_Message* msg, extern "C" { #endif -/* upb_value ******************************************************************/ +#define _kUpb_Status_MaxMessage 127 typedef struct { - uint64_t val; -} upb_value; + bool ok; + char msg[_kUpb_Status_MaxMessage]; /* Error message; NULL-terminated. */ +} upb_Status; -/* Variant that works with a length-delimited rather than NULL-delimited string, - * as supported by strtable. */ -char* upb_strdup2(const char* s, size_t len, upb_Arena* a); +const char* upb_Status_ErrorMessage(const upb_Status* status); +bool upb_Status_IsOk(const upb_Status* status); -UPB_INLINE void _upb_value_setval(upb_value* v, uint64_t val) { v->val = val; } +/* These are no-op if |status| is NULL. */ +void upb_Status_Clear(upb_Status* status); +void upb_Status_SetErrorMessage(upb_Status* status, const char* msg); +void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) + UPB_PRINTF(2, 3); +void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, + va_list args) UPB_PRINTF(2, 0); +void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, + va_list args) UPB_PRINTF(2, 0); -/* For each value ctype, define the following set of functions: - * - * // Get/set an int32 from a upb_value. - * int32_t upb_value_getint32(upb_value val); - * void upb_value_setint32(upb_value *val, int32_t cval); - * - * // Construct a new upb_value from an int32. - * upb_value upb_value_int32(int32_t val); */ -#define FUNCS(name, membername, type_t, converter, proto_type) \ - UPB_INLINE void upb_value_set##name(upb_value* val, type_t cval) { \ - val->val = (converter)cval; \ - } \ - UPB_INLINE upb_value upb_value_##name(type_t val) { \ - upb_value ret; \ - upb_value_set##name(&ret, val); \ - return ret; \ - } \ - UPB_INLINE type_t upb_value_get##name(upb_value val) { \ - return (type_t)(converter)val.val; \ - } +#ifdef __cplusplus +} /* extern "C" */ +#endif -FUNCS(int32, int32, int32_t, int32_t, UPB_CTYPE_INT32) -FUNCS(int64, int64, int64_t, int64_t, UPB_CTYPE_INT64) -FUNCS(uint32, uint32, uint32_t, uint32_t, UPB_CTYPE_UINT32) -FUNCS(uint64, uint64, uint64_t, uint64_t, UPB_CTYPE_UINT64) -FUNCS(bool, _bool, bool, bool, UPB_CTYPE_BOOL) -FUNCS(cstr, cstr, char*, uintptr_t, UPB_CTYPE_CSTR) -FUNCS(ptr, ptr, void*, uintptr_t, UPB_CTYPE_PTR) -FUNCS(constptr, constptr, const void*, uintptr_t, UPB_CTYPE_CONSTPTR) -#undef FUNCS +#endif /* UPB_STATUS_H_ */ -UPB_INLINE void upb_value_setfloat(upb_value* val, float cval) { - memcpy(&val->val, &cval, sizeof(cval)); -} +// Must be last. -UPB_INLINE void upb_value_setdouble(upb_value* val, double cval) { - memcpy(&val->val, &cval, sizeof(cval)); -} +#ifdef __cplusplus +extern "C" { +#endif -UPB_INLINE upb_value upb_value_float(float cval) { - upb_value ret; - upb_value_setfloat(&ret, cval); - return ret; -} +// These types appear in circular references so we need to forward-declare them. +// There is no obviously good place for this so let's just put it here. +typedef struct upb_Array upb_Array; +typedef struct upb_Map upb_Map; -UPB_INLINE upb_value upb_value_double(double cval) { - upb_value ret; - upb_value_setdouble(&ret, cval); - return ret; -} +/* Constants ******************************************************************/ -#undef SET_TYPE +/* A list of types as they are encoded on-the-wire. */ +typedef enum { + kUpb_WireType_Varint = 0, + kUpb_WireType_64Bit = 1, + kUpb_WireType_Delimited = 2, + kUpb_WireType_StartGroup = 3, + kUpb_WireType_EndGroup = 4, + kUpb_WireType_32Bit = 5 +} upb_WireType; -/* upb_tabkey *****************************************************************/ +/* The types a field can have. Note that this list is not identical to the + * types defined in descriptor.proto, which gives INT32 and SINT32 separate + * types (we distinguish the two with the "integer encoding" enum below). */ +typedef enum { + kUpb_CType_Bool = 1, + kUpb_CType_Float = 2, + kUpb_CType_Int32 = 3, + kUpb_CType_UInt32 = 4, + kUpb_CType_Enum = 5, /* Enum values are int32. */ + kUpb_CType_Message = 6, + kUpb_CType_Double = 7, + kUpb_CType_Int64 = 8, + kUpb_CType_UInt64 = 9, + kUpb_CType_String = 10, + kUpb_CType_Bytes = 11 +} upb_CType; -/* Either: - * 1. an actual integer key, or - * 2. a pointer to a string prefixed by its uint32_t length, owned by us. - * - * ...depending on whether this is a string table or an int table. We would - * make this a union of those two types, but C89 doesn't support statically - * initializing a non-first union member. */ -typedef uintptr_t upb_tabkey; +/* The repeated-ness of each field; this matches descriptor.proto. */ +typedef enum { + kUpb_Label_Optional = 1, + kUpb_Label_Required = 2, + kUpb_Label_Repeated = 3 +} upb_Label; -UPB_INLINE char* upb_tabstr(upb_tabkey key, uint32_t* len) { - char* mem = (char*)key; - if (len) memcpy(len, mem, sizeof(*len)); - return mem + sizeof(*len); +/* Descriptor types, as defined in descriptor.proto. */ +typedef enum { + kUpb_FieldType_Double = 1, + kUpb_FieldType_Float = 2, + kUpb_FieldType_Int64 = 3, + kUpb_FieldType_UInt64 = 4, + kUpb_FieldType_Int32 = 5, + kUpb_FieldType_Fixed64 = 6, + kUpb_FieldType_Fixed32 = 7, + kUpb_FieldType_Bool = 8, + kUpb_FieldType_String = 9, + kUpb_FieldType_Group = 10, + kUpb_FieldType_Message = 11, + kUpb_FieldType_Bytes = 12, + kUpb_FieldType_UInt32 = 13, + kUpb_FieldType_Enum = 14, + kUpb_FieldType_SFixed32 = 15, + kUpb_FieldType_SFixed64 = 16, + kUpb_FieldType_SInt32 = 17, + kUpb_FieldType_SInt64 = 18, +} upb_FieldType; + +#define kUpb_FieldType_SizeOf 19 + +#define kUpb_Map_Begin ((size_t)-1) + +UPB_INLINE bool _upb_IsLittleEndian(void) { + int x = 1; + return *(char*)&x == 1; } -UPB_INLINE upb_StringView upb_tabstrview(upb_tabkey key) { - upb_StringView ret; - uint32_t len; - ret.data = upb_tabstr(key, &len); - ret.size = len; - return ret; +UPB_INLINE uint32_t _upb_BigEndian_Swap32(uint32_t val) { + if (_upb_IsLittleEndian()) { + return val; + } else { + return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | + ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24); + } } -/* upb_tabval *****************************************************************/ +UPB_INLINE uint64_t _upb_BigEndian_Swap64(uint64_t val) { + if (_upb_IsLittleEndian()) { + return val; + } else { + return ((uint64_t)_upb_BigEndian_Swap32((uint32_t)val) << 32) | + _upb_BigEndian_Swap32((uint32_t)(val >> 32)); + } +} -typedef struct upb_tabval { - uint64_t val; -} upb_tabval; +UPB_INLINE int _upb_Log2Ceiling(int x) { + if (x <= 1) return 0; +#ifdef __GNUC__ + return 32 - __builtin_clz(x - 1); +#else + int lg2 = 0; + while (1 << lg2 < x) lg2++; + return lg2; +#endif +} -#define UPB_TABVALUE_EMPTY_INIT \ - { -1 } +UPB_INLINE int _upb_Log2CeilingSize(int x) { return 1 << _upb_Log2Ceiling(x); } -/* upb_table ******************************************************************/ +#ifdef __cplusplus +} /* extern "C" */ +#endif -typedef struct _upb_tabent { - upb_tabkey key; - upb_tabval val; - /* Internal chaining. This is const so we can create static initializers for - * tables. We cast away const sometimes, but *only* when the containing - * upb_table is known to be non-const. This requires a bit of care, but - * the subtlety is confined to table.c. */ - const struct _upb_tabent* next; -} upb_tabent; +#endif /* UPB_H_ */ -typedef struct { - size_t count; /* Number of entries in the hash part. */ - uint32_t mask; /* Mask to turn hash value -> bucket. */ - uint32_t max_count; /* Max count before we hit our load limit. */ - uint8_t size_lg2; /* Size of the hashtable part is 2^size_lg2 entries. */ - upb_tabent* entries; -} upb_table; +// Must be last. -typedef struct { - upb_table t; -} upb_strtable; +#ifdef __cplusplus +extern "C" { +#endif -typedef struct { - upb_table t; /* For entries that don't fit in the array part. */ - const upb_tabval* array; /* Array part of the table. See const note above. */ - size_t array_size; /* Array part size. */ - size_t array_count; /* Array part number of elements. */ -} upb_inttable; +// Definitions common to both upb_Array and upb_Map. -UPB_INLINE size_t upb_table_size(const upb_table* t) { - if (t->size_lg2 == 0) - return 0; - else - return 1 << t->size_lg2; -} +typedef union { + bool bool_val; + float float_val; + double double_val; + int32_t int32_val; + int64_t int64_val; + uint32_t uint32_val; + uint64_t uint64_val; + const upb_Array* array_val; + const upb_Map* map_val; + const upb_Message* msg_val; + upb_StringView str_val; +} upb_MessageValue; -/* Internal-only functions, in .h file only out of necessity. */ -UPB_INLINE bool upb_tabent_isempty(const upb_tabent* e) { return e->key == 0; } +typedef union { + upb_Array* array; + upb_Map* map; + upb_Message* msg; +} upb_MutableMessageValue; -/* Initialize and uninitialize a table, respectively. If memory allocation - * failed, false is returned that the table is uninitialized. */ -bool upb_inttable_init(upb_inttable* table, upb_Arena* a); -bool upb_strtable_init(upb_strtable* table, size_t expected_size, upb_Arena* a); +#ifdef __cplusplus +} /* extern "C" */ +#endif -/* Returns the number of values in the table. */ -size_t upb_inttable_count(const upb_inttable* t); -UPB_INLINE size_t upb_strtable_count(const upb_strtable* t) { - return t->t.count; -} -void upb_strtable_clear(upb_strtable* t); +#endif /* UPB_MESSAGE_VALUE_H_ */ -/* Inserts the given key into the hashtable with the given value. The key must - * not already exist in the hash table. For string tables, the key must be - * NULL-terminated, and the table will make an internal copy of the key. - * Inttables must not insert a value of UINTPTR_MAX. - * - * If a table resize was required but memory allocation failed, false is - * returned and the table is unchanged. */ -bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, - upb_Arena* a); -bool upb_strtable_insert(upb_strtable* t, const char* key, size_t len, - upb_value val, upb_Arena* a); +// Must be last. -/* Looks up key in this table, returning "true" if the key was found. - * If v is non-NULL, copies the value for this key into *v. */ -bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v); -bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, - upb_value* v); +#ifdef __cplusplus +extern "C" { +#endif -/* For NULL-terminated strings. */ -UPB_INLINE bool upb_strtable_lookup(const upb_strtable* t, const char* key, - upb_value* v) { - return upb_strtable_lookup2(t, key, strlen(key), v); -} +/* Creates a new array on the given arena that holds elements of this type. */ +upb_Array* upb_Array_New(upb_Arena* a, upb_CType type); -/* Removes an item from the table. Returns true if the remove was successful, - * and stores the removed item in *val if non-NULL. */ -bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val); -bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, - upb_value* val); +/* Returns the number of elements in the array. */ +size_t upb_Array_Size(const upb_Array* arr); -UPB_INLINE bool upb_strtable_remove(upb_strtable* t, const char* key, - upb_value* v) { - return upb_strtable_remove2(t, key, strlen(key), v); -} +/* Returns the given element, which must be within the array's current size. */ +upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i); -/* Updates an existing entry in an inttable. If the entry does not exist, - * returns false and does nothing. Unlike insert/remove, this does not - * invalidate iterators. */ -bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val); +/* Sets the given element, which must be within the array's current size. */ +void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val); -/* Optimizes the table for the current set of entries, for both memory use and - * lookup time. Client should call this after all entries have been inserted; - * inserting more entries is legal, but will likely require a table resize. */ -void upb_inttable_compact(upb_inttable* t, upb_Arena* a); +/* Appends an element to the array. Returns false on allocation failure. */ +bool upb_Array_Append(upb_Array* array, upb_MessageValue val, upb_Arena* arena); -/* Exposed for testing only. */ -bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a); +/* Moves elements within the array using memmove(). Like memmove(), the source + * and destination elements may be overlapping. */ +void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx, + size_t count); -/* Iterators ******************************************************************/ +/* Inserts one or more empty elements into the array. Existing elements are + * shifted right. The new elements have undefined state and must be set with + * `upb_Array_Set()`. + * REQUIRES: `i <= upb_Array_Size(arr)` */ +bool upb_Array_Insert(upb_Array* array, size_t i, size_t count, + upb_Arena* arena); -/* Iteration over inttable. - * - * intptr_t iter = UPB_INTTABLE_BEGIN; - * uintptr_t key; - * upb_value val; - * while (upb_inttable_next2(t, &key, &val, &iter)) { - * // ... - * } - */ +/* Deletes one or more elements from the array. Existing elements are shifted + * left. + * REQUIRES: `i + count <= upb_Array_Size(arr)` */ +void upb_Array_Delete(upb_Array* array, size_t i, size_t count); -#define UPB_INTTABLE_BEGIN -1 +/* Changes the size of a vector. New elements are initialized to empty/0. + * Returns false on allocation failure. */ +bool upb_Array_Resize(upb_Array* array, size_t size, upb_Arena* arena); -bool upb_inttable_next2(const upb_inttable* t, uintptr_t* key, upb_value* val, - intptr_t* iter); -void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter); +#ifdef __cplusplus +} /* extern "C" */ +#endif -/* Iteration over strtable. - * - * intptr_t iter = UPB_INTTABLE_BEGIN; - * upb_StringView key; - * upb_value val; - * while (upb_strtable_next2(t, &key, &val, &iter)) { - * // ... - * } - */ -#define UPB_STRTABLE_BEGIN -1 +#endif /* UPB_ARRAY_H_ */ -bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key, - upb_value* val, intptr_t* iter); -void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter); +// Must be last. -/* DEPRECATED iterators, slated for removal. - * - * Iterators for int and string tables. We are subject to some kind of unusual - * design constraints: - * - * For high-level languages: - * - we must be able to guarantee that we don't crash or corrupt memory even if - * the program accesses an invalidated iterator. - * - * For C++11 range-based for: - * - iterators must be copyable - * - iterators must be comparable - * - it must be possible to construct an "end" value. - * - * Iteration order is undefined. - * - * Modifying the table invalidates iterators. upb_{str,int}table_done() is - * guaranteed to work even on an invalidated iterator, as long as the table it - * is iterating over has not been freed. Calling next() or accessing data from - * an invalidated iterator yields unspecified elements from the table, but it is - * guaranteed not to crash and to return real table elements (except when done() - * is true). */ - -/* upb_strtable_iter **********************************************************/ - -/* upb_strtable_iter i; - * upb_strtable_begin(&i, t); - * for(; !upb_strtable_done(&i); upb_strtable_next(&i)) { - * const char *key = upb_strtable_iter_key(&i); - * const upb_value val = upb_strtable_iter_value(&i); - * // ... - * } - */ +#ifdef __cplusplus +extern "C" { +#endif -typedef struct { - const upb_strtable* t; - size_t index; -} upb_strtable_iter; +/* Our internal representation for repeated fields. */ +struct upb_Array { + uintptr_t data; /* Tagged ptr: low 3 bits of ptr are lg2(elem size). */ + size_t size; /* The number of elements in the array. */ + size_t capacity; /* Allocated storage. Measured in elements. */ +}; -void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t); -void upb_strtable_next(upb_strtable_iter* i); -bool upb_strtable_done(const upb_strtable_iter* i); -upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i); -upb_value upb_strtable_iter_value(const upb_strtable_iter* i); -void upb_strtable_iter_setdone(upb_strtable_iter* i); -bool upb_strtable_iter_isequal(const upb_strtable_iter* i1, - const upb_strtable_iter* i2); +UPB_INLINE const void* _upb_array_constptr(const upb_Array* arr) { + UPB_ASSERT((arr->data & 7) <= 4); + return (void*)(arr->data & ~(uintptr_t)7); +} -/* upb_inttable_iter **********************************************************/ +UPB_INLINE uintptr_t _upb_array_tagptr(void* ptr, int elem_size_lg2) { + UPB_ASSERT(elem_size_lg2 <= 4); + return (uintptr_t)ptr | elem_size_lg2; +} -/* upb_inttable_iter i; - * upb_inttable_begin(&i, t); - * for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { - * uintptr_t key = upb_inttable_iter_key(&i); - * upb_value val = upb_inttable_iter_value(&i); - * // ... - * } - */ +UPB_INLINE void* _upb_array_ptr(upb_Array* arr) { + return (void*)_upb_array_constptr(arr); +} -typedef struct { - const upb_inttable* t; - size_t index; - bool array_part; -} upb_inttable_iter; +UPB_INLINE uintptr_t _upb_tag_arrptr(void* ptr, int elem_size_lg2) { + UPB_ASSERT(elem_size_lg2 <= 4); + UPB_ASSERT(((uintptr_t)ptr & 7) == 0); + return (uintptr_t)ptr | (unsigned)elem_size_lg2; +} -UPB_INLINE const upb_tabent* str_tabent(const upb_strtable_iter* i) { - return &i->t->t.entries[i->index]; +UPB_INLINE upb_Array* _upb_Array_New(upb_Arena* a, size_t init_capacity, + int elem_size_lg2) { + const size_t arr_size = UPB_ALIGN_UP(sizeof(upb_Array), UPB_MALLOC_ALIGN); + const size_t bytes = arr_size + (init_capacity << elem_size_lg2); + upb_Array* arr = (upb_Array*)upb_Arena_Malloc(a, bytes); + if (!arr) return NULL; + arr->data = _upb_tag_arrptr(UPB_PTR_AT(arr, arr_size, void), elem_size_lg2); + arr->size = 0; + arr->capacity = init_capacity; + return arr; } -void upb_inttable_begin(upb_inttable_iter* i, const upb_inttable* t); -void upb_inttable_next(upb_inttable_iter* i); -bool upb_inttable_done(const upb_inttable_iter* i); -uintptr_t upb_inttable_iter_key(const upb_inttable_iter* i); -upb_value upb_inttable_iter_value(const upb_inttable_iter* i); -void upb_inttable_iter_setdone(upb_inttable_iter* i); -bool upb_inttable_iter_isequal(const upb_inttable_iter* i1, - const upb_inttable_iter* i2); +/* Resizes the capacity of the array to be at least min_size. */ +bool _upb_array_realloc(upb_Array* arr, size_t min_size, upb_Arena* arena); -#ifdef __cplusplus -} /* extern "C" */ -#endif +/* Fallback functions for when the accessors require a resize. */ +void* _upb_Array_Resize_fallback(upb_Array** arr_ptr, size_t size, + int elem_size_lg2, upb_Arena* arena); +bool _upb_Array_Append_fallback(upb_Array** arr_ptr, const void* value, + int elem_size_lg2, upb_Arena* arena); +UPB_INLINE bool _upb_array_reserve(upb_Array* arr, size_t size, + upb_Arena* arena) { + if (arr->capacity < size) return _upb_array_realloc(arr, size, arena); + return true; +} -#endif /* UPB_TABLE_H_ */ +UPB_INLINE bool _upb_Array_Resize(upb_Array* arr, size_t size, + upb_Arena* arena) { + if (!_upb_array_reserve(arr, size, arena)) return false; + arr->size = size; + return true; +} -/* Must be last. */ +UPB_INLINE void _upb_array_detach(const void* msg, size_t ofs) { + *UPB_PTR_AT(msg, ofs, upb_Array*) = NULL; +} -#ifdef __cplusplus -extern "C" { -#endif +UPB_INLINE const void* _upb_array_accessor(const void* msg, size_t ofs, + size_t* size) { + const upb_Array* arr = *UPB_PTR_AT(msg, ofs, const upb_Array*); + if (arr) { + if (size) *size = arr->size; + return _upb_array_constptr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} -/** upb_*Int* conversion routines ********************************************/ +UPB_INLINE void* _upb_array_mutable_accessor(void* msg, size_t ofs, + size_t* size) { + upb_Array* arr = *UPB_PTR_AT(msg, ofs, upb_Array*); + if (arr) { + if (size) *size = arr->size; + return _upb_array_ptr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} -UPB_INLINE int32_t _upb_Int32_FromI(int v) { return (int32_t)v; } +UPB_INLINE void* _upb_Array_Resize_accessor2(void* msg, size_t ofs, size_t size, + int elem_size_lg2, + upb_Arena* arena) { + upb_Array** arr_ptr = UPB_PTR_AT(msg, ofs, upb_Array*); + upb_Array* arr = *arr_ptr; + if (!arr || arr->capacity < size) { + return _upb_Array_Resize_fallback(arr_ptr, size, elem_size_lg2, arena); + } + arr->size = size; + return _upb_array_ptr(arr); +} -UPB_INLINE int64_t _upb_Int64_FromLL(long long v) { return (int64_t)v; } +UPB_INLINE bool _upb_Array_Append_accessor2(void* msg, size_t ofs, + int elem_size_lg2, + const void* value, + upb_Arena* arena) { + upb_Array** arr_ptr = UPB_PTR_AT(msg, ofs, upb_Array*); + size_t elem_size = 1 << elem_size_lg2; + upb_Array* arr = *arr_ptr; + void* ptr; + if (!arr || arr->size == arr->capacity) { + return _upb_Array_Append_fallback(arr_ptr, value, elem_size_lg2, arena); + } + ptr = _upb_array_ptr(arr); + memcpy(UPB_PTR_AT(ptr, arr->size * elem_size, char), value, elem_size); + arr->size++; + return true; +} -UPB_INLINE uint32_t _upb_UInt32_FromU(unsigned v) { return (uint32_t)v; } +/* Used by old generated code, remove once all code has been regenerated. */ +UPB_INLINE int _upb_sizelg2(upb_CType type) { + switch (type) { + case kUpb_CType_Bool: + return 0; + case kUpb_CType_Float: + case kUpb_CType_Int32: + case kUpb_CType_UInt32: + case kUpb_CType_Enum: + return 2; + case kUpb_CType_Message: + return UPB_SIZE(2, 3); + case kUpb_CType_Double: + case kUpb_CType_Int64: + case kUpb_CType_UInt64: + return 3; + case kUpb_CType_String: + case kUpb_CType_Bytes: + return UPB_SIZE(3, 4); + } + UPB_UNREACHABLE(); +} -UPB_INLINE uint64_t _upb_UInt64_FromULL(unsigned long long v) { - return (uint64_t)v; +UPB_INLINE void* _upb_Array_Resize_accessor(void* msg, size_t ofs, size_t size, + upb_CType type, upb_Arena* arena) { + return _upb_Array_Resize_accessor2(msg, ofs, size, _upb_sizelg2(type), arena); } -/** upb_MiniTable *************************************************************/ +UPB_INLINE bool _upb_Array_Append_accessor(void* msg, size_t ofs, + size_t elem_size, upb_CType type, + const void* value, + upb_Arena* arena) { + (void)elem_size; + return _upb_Array_Append_accessor2(msg, ofs, _upb_sizelg2(type), value, + arena); +} -/* upb_MiniTable represents the memory layout of a given upb_MessageDef. The - * members are public so generated code can initialize them, but users MUST NOT - * read or write any of its members. */ +#ifdef __cplusplus +} /* extern "C" */ +#endif -typedef struct { - uint32_t number; - uint16_t offset; - int16_t presence; // If >0, hasbit_index. If <0, ~oneof_index - uint16_t submsg_index; // undefined if descriptortype != MESSAGE/GROUP/ENUM - uint8_t descriptortype; - uint8_t mode; /* upb_FieldMode | upb_LabelFlags | - (upb_FieldRep << upb_FieldRep_Shift) */ -} upb_MiniTable_Field; -typedef enum { - kUpb_FieldMode_Map = 0, - kUpb_FieldMode_Array = 1, - kUpb_FieldMode_Scalar = 2, +#endif /* UPB_INTERNAL_ARRAY_H_ */ - kUpb_FieldMode_Mask = 3, /* Mask to isolate the mode from upb_FieldRep. */ -} upb_FieldMode; +#ifndef UPB_INTERNAL_ATOI_H_ +#define UPB_INTERNAL_ATOI_H_ -/* Extra flags on the mode field. */ -enum upb_LabelFlags { - upb_LabelFlags_IsPacked = 4, - upb_LabelFlags_IsExtension = 8, -}; +// Must be last. -/* Representation in the message. Derivable from descriptortype and mode, but - * fast access helps the serializer. */ -enum upb_FieldRep { - upb_FieldRep_1Byte = 0, - upb_FieldRep_4Byte = 1, - upb_FieldRep_8Byte = 2, - upb_FieldRep_StringView = 3, +#ifdef __cplusplus +extern "C" { +#endif -#if UINTPTR_MAX == 0xffffffff - upb_FieldRep_Pointer = upb_FieldRep_4Byte, -#else - upb_FieldRep_Pointer = upb_FieldRep_8Byte, +// We use these hand-written routines instead of strto[u]l() because the "long +// long" variants aren't in c89. Also our version allows setting a ptr limit. +// Return the new position of the pointer after parsing the int, or NULL on +// integer overflow. + +const char* upb_BufToUint64(const char* ptr, const char* end, uint64_t* val); +const char* upb_BufToInt64(const char* ptr, const char* end, int64_t* val, + bool* is_neg); + +#ifdef __cplusplus +} /* extern "C" */ #endif - upb_FieldRep_Shift = - 6, /* Bit offset of the rep in upb_MiniTable_Field.mode */ -}; -UPB_INLINE upb_FieldMode upb_FieldMode_Get(const upb_MiniTable_Field* field) { - return (upb_FieldMode)(field->mode & 3); -} +#endif /* UPB_INTERNAL_ATOI_H_ */ -UPB_INLINE bool upb_IsRepeatedOrMap(const upb_MiniTable_Field* field) { - /* This works because upb_FieldMode has no value 3. */ - return !(field->mode & kUpb_FieldMode_Scalar); -} +#ifndef UPB_MAP_H_ +#define UPB_MAP_H_ -UPB_INLINE bool upb_IsSubMessage(const upb_MiniTable_Field* field) { - return field->descriptortype == kUpb_FieldType_Message || - field->descriptortype == kUpb_FieldType_Group; -} -struct upb_Decoder; -struct upb_MiniTable; +// Must be last. -typedef const char* _upb_FieldParser(struct upb_Decoder* d, const char* ptr, - upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t data); +#ifdef __cplusplus +extern "C" { +#endif -typedef struct { - uint64_t field_data; - _upb_FieldParser* field_parser; -} _upb_FastTable_Entry; +/* Creates a new map on the given arena with the given key/value size. */ +upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type); -typedef struct { - const int32_t* values; // List of values <0 or >63 - uint64_t mask; // Bits are set for acceptable value 0 <= x < 64 - int value_count; -} upb_MiniTable_Enum; +/* Returns the number of entries in the map. */ +size_t upb_Map_Size(const upb_Map* map); -UPB_INLINE bool upb_MiniTable_Enum_CheckValue(const upb_MiniTable_Enum* e, - int32_t val) { - uint32_t uval = (uint32_t)val; - if (uval < 64) return e->mask & (1 << uval); - // OPT: binary search long lists? - int n = e->value_count; - for (int i = 0; i < n; i++) { - if (e->values[i] == val) return true; - } - return false; -} +/* Stores a value for the given key into |*val| (or the zero value if the key is + * not present). Returns whether the key was present. The |val| pointer may be + * NULL, in which case the function tests whether the given key is present. */ +bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, + upb_MessageValue* val); -typedef union { - const struct upb_MiniTable* submsg; - const upb_MiniTable_Enum* subenum; -} upb_MiniTable_Sub; +/* Removes all entries in the map. */ +void upb_Map_Clear(upb_Map* map); typedef enum { - upb_ExtMode_NonExtendable = 0, // Non-extendable message. - upb_ExtMode_Extendable = 1, // Normal extendable message. - upb_ExtMode_IsMessageSet = 2, // MessageSet message. - upb_ExtMode_IsMessageSet_ITEM = - 3, // MessageSet item (temporary only, see decode.c) -} upb_ExtMode; + // LINT.IfChange + kUpb_MapInsertStatus_Inserted = 0, + kUpb_MapInsertStatus_Replaced = 1, + kUpb_MapInsertStatus_OutOfMemory = 2, + // LINT.ThenChange(//depot/google3/third_party/upb/upb/msg_internal.h) +} upb_MapInsertStatus; + +/* Sets the given key to the given value, returning whether the key was inserted + * or replaced. If the key was inserted, then any existing iterators will be + * invalidated. */ +upb_MapInsertStatus upb_Map_Insert(upb_Map* map, upb_MessageValue key, + upb_MessageValue val, upb_Arena* arena); + +/* Sets the given key to the given value. Returns false if memory allocation + * failed. If the key is newly inserted, then any existing iterators will be + * invalidated. */ +UPB_INLINE bool upb_Map_Set(upb_Map* map, upb_MessageValue key, + upb_MessageValue val, upb_Arena* arena) { + return upb_Map_Insert(map, key, val, arena) != + kUpb_MapInsertStatus_OutOfMemory; +} -/* MessageSet wire format is: - * message MessageSet { - * repeated group Item = 1 { - * required int32 type_id = 2; - * required string message = 3; - * } - * } +/* Deletes this key from the table. Returns true if the key was present. */ +bool upb_Map_Delete(upb_Map* map, upb_MessageValue key); + +/* Map iteration: + * + * size_t iter = kUpb_Map_Begin; + * while (upb_MapIterator_Next(map, &iter)) { + * upb_MessageValue key = upb_MapIterator_Key(map, iter); + * upb_MessageValue val = upb_MapIterator_Value(map, iter); + * + * // If mutating is desired. + * upb_MapIterator_SetValue(map, iter, value2); + * } */ -typedef enum { - _UPB_MSGSET_ITEM = 1, - _UPB_MSGSET_TYPEID = 2, - _UPB_MSGSET_MESSAGE = 3, -} upb_msgext_fieldnum; -struct upb_MiniTable { - const upb_MiniTable_Sub* subs; - const upb_MiniTable_Field* fields; - /* Must be aligned to sizeof(void*). Doesn't include internal members like - * unknown fields, extension dict, pointer to msglayout, etc. */ - uint16_t size; - uint16_t field_count; - uint8_t ext; // upb_ExtMode, declared as uint8_t so sizeof(ext) == 1 - uint8_t dense_below; - uint8_t table_mask; - uint8_t required_count; // Required fields have the lowest hasbits. - /* To statically initialize the tables of variable length, we need a flexible - * array member, and we need to compile in gnu99 mode (constant initialization - * of flexible array members is a GNU extension, not in C99 unfortunately. */ - _upb_FastTable_Entry fasttable[]; -}; +/* Advances to the next entry. Returns false if no more entries are present. */ +bool upb_MapIterator_Next(const upb_Map* map, size_t* iter); -typedef struct { - upb_MiniTable_Field field; - const upb_MiniTable* extendee; - upb_MiniTable_Sub sub; /* NULL unless submessage or proto2 enum */ -} upb_MiniTable_Extension; +/* Returns true if the iterator still points to a valid entry, or false if the + * iterator is past the last element. It is an error to call this function with + * kUpb_Map_Begin (you must call next() at least once first). */ +bool upb_MapIterator_Done(const upb_Map* map, size_t iter); -typedef struct { - const upb_MiniTable** msgs; - const upb_MiniTable_Enum** enums; - const upb_MiniTable_Extension** exts; - int msg_count; - int enum_count; - int ext_count; -} upb_MiniTable_File; +/* Returns the key and value for this entry of the map. */ +upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter); +upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter); -// Computes a bitmask in which the |l->required_count| lowest bits are set, -// except that we skip the lowest bit (because upb never uses hasbit 0). -// -// Sample output: -// requiredmask(1) => 0b10 (0x2) -// requiredmask(5) => 0b111110 (0x3e) -UPB_INLINE uint64_t upb_MiniTable_requiredmask(const upb_MiniTable* l) { - int n = l->required_count; - assert(0 < n && n <= 63); - return ((1ULL << n) - 1) << 1; -} +/* Sets the value for this entry. The iterator must not be done, and the + * iterator must not have been initialized const. */ +void upb_MapIterator_SetValue(upb_Map* map, size_t iter, + upb_MessageValue value); -/** upb_ExtensionRegistry - * ****************************************************************/ +#ifdef __cplusplus +} /* extern "C" */ +#endif -/* Adds the given extension info for message type |l| and field number |num| - * into the registry. Returns false if this message type and field number were - * already in the map, or if memory allocation fails. */ -bool _upb_extreg_add(upb_ExtensionRegistry* r, - const upb_MiniTable_Extension** e, size_t count); -/* Looks up the extension (if any) defined for message type |l| and field - * number |num|. If an extension was found, copies the field info into |*ext| - * and returns true. Otherwise returns false. */ -const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r, - const upb_MiniTable* l, - uint32_t num); +#endif /* UPB_MAP_H_ */ -/** upb_Message - * *******************************************************************/ +/* +** Our memory representation for parsing tables and messages themselves. +** Functions in this file are used by generated code and possibly reflection. +** +** The definitions in this file are internal to upb. +**/ -/* Internal members of a upb_Message that track unknown fields and/or - * extensions. We can change this without breaking binary compatibility. We put - * these before the user's data. The user's upb_Message* points after the - * upb_Message_Internal. */ +#ifndef UPB_MSG_INT_H_ +#define UPB_MSG_INT_H_ -typedef struct { - /* Total size of this structure, including the data that follows. - * Must be aligned to 8, which is alignof(upb_Message_Extension) */ - uint32_t size; +#include +#include - /* Offsets relative to the beginning of this structure. - * - * Unknown data grows forward from the beginning to unknown_end. - * Extension data grows backward from size to ext_begin. - * When the two meet, we're out of data and have to realloc. - * - * If we imagine that the final member of this struct is: - * char data[size - overhead]; // overhead = - * sizeof(upb_Message_InternalData) - * - * Then we have: - * unknown data: data[0 .. (unknown_end - overhead)] - * extensions data: data[(ext_begin - overhead) .. (size - overhead)] */ - uint32_t unknown_end; - uint32_t ext_begin; - /* Data follows, as if there were an array: - * char data[size - sizeof(upb_Message_InternalData)]; */ -} upb_Message_InternalData; -typedef struct { - upb_Message_InternalData* internal; - /* Message data follows. */ -} upb_Message_Internal; +#ifndef UPB_EXTENSION_REGISTRY_H_ +#define UPB_EXTENSION_REGISTRY_H_ -/* Maps upb_CType -> memory size. */ -extern char _upb_CTypeo_size[12]; -UPB_INLINE size_t upb_msg_sizeof(const upb_MiniTable* l) { - return l->size + sizeof(upb_Message_Internal); -} +// Must be last. -UPB_INLINE upb_Message* _upb_Message_New_inl(const upb_MiniTable* l, - upb_Arena* a) { - size_t size = upb_msg_sizeof(l); - void* mem = upb_Arena_Malloc(a, size); - upb_Message* msg; - if (UPB_UNLIKELY(!mem)) return NULL; - msg = UPB_PTR_AT(mem, sizeof(upb_Message_Internal), upb_Message); - memset(mem, 0, size); - return msg; -} +#ifdef __cplusplus +extern "C" { +#endif -/* Creates a new messages with the given layout on the given arena. */ -upb_Message* _upb_Message_New(const upb_MiniTable* l, upb_Arena* a); +/* Extension registry: a dynamic data structure that stores a map of: + * (upb_MiniTable, number) -> extension info + * + * upb_decode() uses upb_ExtensionRegistry to look up extensions while parsing + * binary format. + * + * upb_ExtensionRegistry is part of the mini-table (msglayout) family of + * objects. Like all mini-table objects, it is suitable for reflection-less + * builds that do not want to expose names into the binary. + * + * Unlike most mini-table types, upb_ExtensionRegistry requires dynamic memory + * allocation and dynamic initialization: + * * If reflection is being used, then upb_DefPool will construct an appropriate + * upb_ExtensionRegistry automatically. + * * For a mini-table only build, the user must manually construct the + * upb_ExtensionRegistry and populate it with all of the extensions the user + * cares about. + * * A third alternative is to manually unpack relevant extensions after the + * main parse is complete, similar to how Any works. This is perhaps the + * nicest solution from the perspective of reducing dependencies, avoiding + * dynamic memory allocation, and avoiding the need to parse uninteresting + * extensions. The downsides are: + * (1) parse errors are not caught during the main parse + * (2) the CPU hit of parsing comes during access, which could cause an + * undesirable stutter in application performance. + * + * Users cannot directly get or put into this map. Users can only add the + * extensions from a generated module and pass the extension registry to the + * binary decoder. + * + * A upb_DefPool provides a upb_ExtensionRegistry, so any users who use + * reflection do not need to populate a upb_ExtensionRegistry directly. + */ -UPB_INLINE upb_Message_Internal* upb_Message_Getinternal(upb_Message* msg) { - ptrdiff_t size = sizeof(upb_Message_Internal); - return (upb_Message_Internal*)((char*)msg - size); -} +typedef struct upb_ExtensionRegistry upb_ExtensionRegistry; -/* Clears the given message. */ -void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l); +// Creates a upb_ExtensionRegistry in the given arena. +// The arena must outlive any use of the extreg. +upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena); -/* Discards the unknown fields for this message only. */ -void _upb_Message_DiscardUnknown_shallow(upb_Message* msg); +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// -/* Adds unknown data (serialized protobuf data) to the given message. The data - * is copied into the message instance. */ -bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, - upb_Arena* arena); +typedef struct upb_MiniTable upb_MiniTable; +typedef struct upb_MiniTable_Extension upb_MiniTable_Extension; -/** upb_Message_Extension - * ***************************************************************/ +// Adds the given extension info for message type |l| and field number |num| +// into the registry. Returns false if this message type and field number were +// already in the map, or if memory allocation fails. +bool _upb_extreg_add(upb_ExtensionRegistry* r, + const upb_MiniTable_Extension** e, size_t count); -/* The internal representation of an extension is self-describing: it contains - * enough information that we can serialize it to binary format without needing - * to look it up in a upb_ExtensionRegistry. - * - * This representation allocates 16 bytes to data on 64-bit platforms. This is - * rather wasteful for scalars (in the extreme case of bool, it wastes 15 - * bytes). We accept this because we expect messages to be the most common - * extension type. */ -typedef struct { - const upb_MiniTable_Extension* ext; - union { - upb_StringView str; - void* ptr; - char scalar_data[8]; - } data; -} upb_Message_Extension; +// Looks up the extension (if any) defined for message type |l| and field +// number |num|. If an extension was found, copies the field info into |*ext| +// and returns true. Otherwise returns false. +const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r, + const upb_MiniTable* l, + uint32_t num); -/* Adds the given extension data to the given message. |ext| is copied into the - * message instance. This logically replaces any previously-added extension with - * this number */ -upb_Message_Extension* _upb_Message_Getorcreateext( - upb_Message* msg, const upb_MiniTable_Extension* ext, upb_Arena* arena); +#ifdef __cplusplus +} /* extern "C" */ +#endif -/* Returns an array of extensions for this message. Note: the array is - * ordered in reverse relative to the order of creation. */ -const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg, - size_t* count); -/* Returns an extension for the given field number, or NULL if no extension - * exists for this field number. */ -const upb_Message_Extension* _upb_Message_Getext( - const upb_Message* msg, const upb_MiniTable_Extension* ext); +#endif /* UPB_EXTENSION_REGISTRY_H_ */ -void _upb_Message_Clearext(upb_Message* msg, - const upb_MiniTable_Extension* ext); +/* + * upb_table + * + * This header is INTERNAL-ONLY! Its interfaces are not public or stable! + * This file defines very fast int->upb_value (inttable) and string->upb_value + * (strtable) hash tables. + * + * The table uses chained scatter with Brent's variation (inspired by the Lua + * implementation of hash tables). The hash function for strings is Austin + * Appleby's "MurmurHash." + * + * The inttable uses uintptr_t as its key, which guarantees it can be used to + * store pointers or integers of at least 32 bits (upb isn't really useful on + * systems where sizeof(void*) < 4). + * + * The table must be homogeneous (all values of the same type). In debug + * mode, we check this on insert and lookup. + */ -void _upb_Message_Clearext(upb_Message* msg, - const upb_MiniTable_Extension* ext); +#ifndef UPB_INTERNAL_TABLE_H_ +#define UPB_INTERNAL_TABLE_H_ -/** Hasbit access *************************************************************/ +#include -UPB_INLINE bool _upb_hasbit(const upb_Message* msg, size_t idx) { - return (*UPB_PTR_AT(msg, idx / 8, const char) & (1 << (idx % 8))) != 0; -} -UPB_INLINE void _upb_sethas(const upb_Message* msg, size_t idx) { - (*UPB_PTR_AT(msg, idx / 8, char)) |= (char)(1 << (idx % 8)); -} +// Must be last. -UPB_INLINE void _upb_clearhas(const upb_Message* msg, size_t idx) { - (*UPB_PTR_AT(msg, idx / 8, char)) &= (char)(~(1 << (idx % 8))); -} +#ifdef __cplusplus +extern "C" { +#endif -UPB_INLINE size_t _upb_Message_Hasidx(const upb_MiniTable_Field* f) { - UPB_ASSERT(f->presence > 0); - return f->presence; -} +/* upb_value ******************************************************************/ -UPB_INLINE bool _upb_hasbit_field(const upb_Message* msg, - const upb_MiniTable_Field* f) { - return _upb_hasbit(msg, _upb_Message_Hasidx(f)); -} +typedef struct { + uint64_t val; +} upb_value; -UPB_INLINE void _upb_sethas_field(const upb_Message* msg, - const upb_MiniTable_Field* f) { - _upb_sethas(msg, _upb_Message_Hasidx(f)); -} +/* Variant that works with a length-delimited rather than NULL-delimited string, + * as supported by strtable. */ +char* upb_strdup2(const char* s, size_t len, upb_Arena* a); -UPB_INLINE void _upb_clearhas_field(const upb_Message* msg, - const upb_MiniTable_Field* f) { - _upb_clearhas(msg, _upb_Message_Hasidx(f)); -} +UPB_INLINE void _upb_value_setval(upb_value* v, uint64_t val) { v->val = val; } -/** Oneof case access *********************************************************/ +/* For each value ctype, define the following set of functions: + * + * // Get/set an int32 from a upb_value. + * int32_t upb_value_getint32(upb_value val); + * void upb_value_setint32(upb_value *val, int32_t cval); + * + * // Construct a new upb_value from an int32. + * upb_value upb_value_int32(int32_t val); */ +#define FUNCS(name, membername, type_t, converter, proto_type) \ + UPB_INLINE void upb_value_set##name(upb_value* val, type_t cval) { \ + val->val = (converter)cval; \ + } \ + UPB_INLINE upb_value upb_value_##name(type_t val) { \ + upb_value ret; \ + upb_value_set##name(&ret, val); \ + return ret; \ + } \ + UPB_INLINE type_t upb_value_get##name(upb_value val) { \ + return (type_t)(converter)val.val; \ + } -UPB_INLINE uint32_t* _upb_oneofcase(upb_Message* msg, size_t case_ofs) { - return UPB_PTR_AT(msg, case_ofs, uint32_t); +FUNCS(int32, int32, int32_t, int32_t, UPB_CTYPE_INT32) +FUNCS(int64, int64, int64_t, int64_t, UPB_CTYPE_INT64) +FUNCS(uint32, uint32, uint32_t, uint32_t, UPB_CTYPE_UINT32) +FUNCS(uint64, uint64, uint64_t, uint64_t, UPB_CTYPE_UINT64) +FUNCS(bool, _bool, bool, bool, UPB_CTYPE_BOOL) +FUNCS(cstr, cstr, char*, uintptr_t, UPB_CTYPE_CSTR) +FUNCS(ptr, ptr, void*, uintptr_t, UPB_CTYPE_PTR) +FUNCS(constptr, constptr, const void*, uintptr_t, UPB_CTYPE_CONSTPTR) + +#undef FUNCS + +UPB_INLINE void upb_value_setfloat(upb_value* val, float cval) { + memcpy(&val->val, &cval, sizeof(cval)); } -UPB_INLINE uint32_t _upb_getoneofcase(const void* msg, size_t case_ofs) { - return *UPB_PTR_AT(msg, case_ofs, uint32_t); +UPB_INLINE void upb_value_setdouble(upb_value* val, double cval) { + memcpy(&val->val, &cval, sizeof(cval)); } -UPB_INLINE size_t _upb_oneofcase_ofs(const upb_MiniTable_Field* f) { - UPB_ASSERT(f->presence < 0); - return ~(ptrdiff_t)f->presence; +UPB_INLINE upb_value upb_value_float(float cval) { + upb_value ret; + upb_value_setfloat(&ret, cval); + return ret; } -UPB_INLINE uint32_t* _upb_oneofcase_field(upb_Message* msg, - const upb_MiniTable_Field* f) { - return _upb_oneofcase(msg, _upb_oneofcase_ofs(f)); +UPB_INLINE upb_value upb_value_double(double cval) { + upb_value ret; + upb_value_setdouble(&ret, cval); + return ret; } -UPB_INLINE uint32_t _upb_getoneofcase_field(const upb_Message* msg, - const upb_MiniTable_Field* f) { - return _upb_getoneofcase(msg, _upb_oneofcase_ofs(f)); +#undef SET_TYPE + +/* upb_tabkey *****************************************************************/ + +/* Either: + * 1. an actual integer key, or + * 2. a pointer to a string prefixed by its uint32_t length, owned by us. + * + * ...depending on whether this is a string table or an int table. We would + * make this a union of those two types, but C89 doesn't support statically + * initializing a non-first union member. */ +typedef uintptr_t upb_tabkey; + +UPB_INLINE char* upb_tabstr(upb_tabkey key, uint32_t* len) { + char* mem = (char*)key; + if (len) memcpy(len, mem, sizeof(*len)); + return mem + sizeof(*len); } -UPB_INLINE bool _upb_has_submsg_nohasbit(const upb_Message* msg, size_t ofs) { - return *UPB_PTR_AT(msg, ofs, const upb_Message*) != NULL; +UPB_INLINE upb_StringView upb_tabstrview(upb_tabkey key) { + upb_StringView ret; + uint32_t len; + ret.data = upb_tabstr(key, &len); + ret.size = len; + return ret; } -/** upb_Array *****************************************************************/ +/* upb_tabval *****************************************************************/ + +typedef struct upb_tabval { + uint64_t val; +} upb_tabval; + +#define UPB_TABVALUE_EMPTY_INIT \ + { -1 } + +/* upb_table ******************************************************************/ + +typedef struct _upb_tabent { + upb_tabkey key; + upb_tabval val; + + /* Internal chaining. This is const so we can create static initializers for + * tables. We cast away const sometimes, but *only* when the containing + * upb_table is known to be non-const. This requires a bit of care, but + * the subtlety is confined to table.c. */ + const struct _upb_tabent* next; +} upb_tabent; -/* Our internal representation for repeated fields. */ typedef struct { - uintptr_t data; /* Tagged ptr: low 3 bits of ptr are lg2(elem size). */ - size_t len; /* Measured in elements. */ - size_t size; /* Measured in elements. */ - uint64_t junk; -} upb_Array; + size_t count; /* Number of entries in the hash part. */ + uint32_t mask; /* Mask to turn hash value -> bucket. */ + uint32_t max_count; /* Max count before we hit our load limit. */ + uint8_t size_lg2; /* Size of the hashtable part is 2^size_lg2 entries. */ + upb_tabent* entries; +} upb_table; -UPB_INLINE const void* _upb_array_constptr(const upb_Array* arr) { - UPB_ASSERT((arr->data & 7) <= 4); - return (void*)(arr->data & ~(uintptr_t)7); -} +typedef struct { + upb_table t; +} upb_strtable; -UPB_INLINE uintptr_t _upb_array_tagptr(void* ptr, int elem_size_lg2) { - UPB_ASSERT(elem_size_lg2 <= 4); - return (uintptr_t)ptr | elem_size_lg2; -} +typedef struct { + upb_table t; /* For entries that don't fit in the array part. */ + const upb_tabval* array; /* Array part of the table. See const note above. */ + size_t array_size; /* Array part size. */ + size_t array_count; /* Array part number of elements. */ +} upb_inttable; -UPB_INLINE void* _upb_array_ptr(upb_Array* arr) { - return (void*)_upb_array_constptr(arr); +UPB_INLINE size_t upb_table_size(const upb_table* t) { + if (t->size_lg2 == 0) + return 0; + else + return 1 << t->size_lg2; } -UPB_INLINE uintptr_t _upb_tag_arrptr(void* ptr, int elem_size_lg2) { - UPB_ASSERT(elem_size_lg2 <= 4); - UPB_ASSERT(((uintptr_t)ptr & 7) == 0); - return (uintptr_t)ptr | (unsigned)elem_size_lg2; -} +/* Internal-only functions, in .h file only out of necessity. */ +UPB_INLINE bool upb_tabent_isempty(const upb_tabent* e) { return e->key == 0; } -UPB_INLINE upb_Array* _upb_Array_New(upb_Arena* a, size_t init_size, - int elem_size_lg2) { - const size_t arr_size = UPB_ALIGN_UP(sizeof(upb_Array), 8); - const size_t bytes = sizeof(upb_Array) + (init_size << elem_size_lg2); - upb_Array* arr = (upb_Array*)upb_Arena_Malloc(a, bytes); - if (!arr) return NULL; - arr->data = _upb_tag_arrptr(UPB_PTR_AT(arr, arr_size, void), elem_size_lg2); - arr->len = 0; - arr->size = init_size; - return arr; +/* Initialize and uninitialize a table, respectively. If memory allocation + * failed, false is returned that the table is uninitialized. */ +bool upb_inttable_init(upb_inttable* table, upb_Arena* a); +bool upb_strtable_init(upb_strtable* table, size_t expected_size, upb_Arena* a); + +/* Returns the number of values in the table. */ +size_t upb_inttable_count(const upb_inttable* t); +UPB_INLINE size_t upb_strtable_count(const upb_strtable* t) { + return t->t.count; } -/* Resizes the capacity of the array to be at least min_size. */ -bool _upb_array_realloc(upb_Array* arr, size_t min_size, upb_Arena* arena); +void upb_strtable_clear(upb_strtable* t); -/* Fallback functions for when the accessors require a resize. */ -void* _upb_Array_Resize_fallback(upb_Array** arr_ptr, size_t size, - int elem_size_lg2, upb_Arena* arena); -bool _upb_Array_Append_fallback(upb_Array** arr_ptr, const void* value, - int elem_size_lg2, upb_Arena* arena); +/* Inserts the given key into the hashtable with the given value. The key must + * not already exist in the hash table. For strtables, the key is not required + * to be NULL-terminated, and the table will make an internal copy of the key. + * Inttables must not insert a value of UINTPTR_MAX. + * + * If a table resize was required but memory allocation failed, false is + * returned and the table is unchanged. */ +bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, + upb_Arena* a); +bool upb_strtable_insert(upb_strtable* t, const char* key, size_t len, + upb_value val, upb_Arena* a); -UPB_INLINE bool _upb_array_reserve(upb_Array* arr, size_t size, - upb_Arena* arena) { - if (arr->size < size) return _upb_array_realloc(arr, size, arena); - return true; -} +/* Looks up key in this table, returning "true" if the key was found. + * If v is non-NULL, copies the value for this key into *v. */ +bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v); +bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, + upb_value* v); -UPB_INLINE bool _upb_Array_Resize(upb_Array* arr, size_t size, - upb_Arena* arena) { - if (!_upb_array_reserve(arr, size, arena)) return false; - arr->len = size; - return true; +/* For NULL-terminated strings. */ +UPB_INLINE bool upb_strtable_lookup(const upb_strtable* t, const char* key, + upb_value* v) { + return upb_strtable_lookup2(t, key, strlen(key), v); } -UPB_INLINE const void* _upb_array_accessor(const void* msg, size_t ofs, - size_t* size) { - const upb_Array* arr = *UPB_PTR_AT(msg, ofs, const upb_Array*); - if (arr) { - if (size) *size = arr->len; - return _upb_array_constptr(arr); - } else { - if (size) *size = 0; - return NULL; - } -} +/* Removes an item from the table. Returns true if the remove was successful, + * and stores the removed item in *val if non-NULL. */ +bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val); +bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, + upb_value* val); -UPB_INLINE void* _upb_array_mutable_accessor(void* msg, size_t ofs, - size_t* size) { - upb_Array* arr = *UPB_PTR_AT(msg, ofs, upb_Array*); - if (arr) { - if (size) *size = arr->len; - return _upb_array_ptr(arr); - } else { - if (size) *size = 0; - return NULL; - } +UPB_INLINE bool upb_strtable_remove(upb_strtable* t, const char* key, + upb_value* v) { + return upb_strtable_remove2(t, key, strlen(key), v); } -UPB_INLINE void* _upb_Array_Resize_accessor2(void* msg, size_t ofs, size_t size, - int elem_size_lg2, - upb_Arena* arena) { - upb_Array** arr_ptr = UPB_PTR_AT(msg, ofs, upb_Array*); - upb_Array* arr = *arr_ptr; - if (!arr || arr->size < size) { - return _upb_Array_Resize_fallback(arr_ptr, size, elem_size_lg2, arena); - } - arr->len = size; - return _upb_array_ptr(arr); -} - -UPB_INLINE bool _upb_Array_Append_accessor2(void* msg, size_t ofs, - int elem_size_lg2, - const void* value, - upb_Arena* arena) { - upb_Array** arr_ptr = UPB_PTR_AT(msg, ofs, upb_Array*); - size_t elem_size = 1 << elem_size_lg2; - upb_Array* arr = *arr_ptr; - void* ptr; - if (!arr || arr->len == arr->size) { - return _upb_Array_Append_fallback(arr_ptr, value, elem_size_lg2, arena); - } - ptr = _upb_array_ptr(arr); - memcpy(UPB_PTR_AT(ptr, arr->len * elem_size, char), value, elem_size); - arr->len++; - return true; -} +/* Updates an existing entry in an inttable. If the entry does not exist, + * returns false and does nothing. Unlike insert/remove, this does not + * invalidate iterators. */ +bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val); -/* Used by old generated code, remove once all code has been regenerated. */ -UPB_INLINE int _upb_sizelg2(upb_CType type) { - switch (type) { - case kUpb_CType_Bool: - return 0; - case kUpb_CType_Float: - case kUpb_CType_Int32: - case kUpb_CType_UInt32: - case kUpb_CType_Enum: - return 2; - case kUpb_CType_Message: - return UPB_SIZE(2, 3); - case kUpb_CType_Double: - case kUpb_CType_Int64: - case kUpb_CType_UInt64: - return 3; - case kUpb_CType_String: - case kUpb_CType_Bytes: - return UPB_SIZE(3, 4); - } - UPB_UNREACHABLE(); -} -UPB_INLINE void* _upb_Array_Resize_accessor(void* msg, size_t ofs, size_t size, - upb_CType type, upb_Arena* arena) { - return _upb_Array_Resize_accessor2(msg, ofs, size, _upb_sizelg2(type), arena); -} -UPB_INLINE bool _upb_Array_Append_accessor(void* msg, size_t ofs, - size_t elem_size, upb_CType type, - const void* value, - upb_Arena* arena) { - (void)elem_size; - return _upb_Array_Append_accessor2(msg, ofs, _upb_sizelg2(type), value, - arena); -} +/* Optimizes the table for the current set of entries, for both memory use and + * lookup time. Client should call this after all entries have been inserted; + * inserting more entries is legal, but will likely require a table resize. */ +void upb_inttable_compact(upb_inttable* t, upb_Arena* a); -/** upb_Map *******************************************************************/ +/* Exposed for testing only. */ +bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a); -/* Right now we use strmaps for everything. We'll likely want to use - * integer-specific maps for integer-keyed maps.*/ -typedef struct { - /* Size of key and val, based on the map type. Strings are represented as '0' - * because they must be handled specially. */ - char key_size; - char val_size; +/* Iterators ******************************************************************/ - upb_strtable table; -} upb_Map; +/* Iteration over inttable. + * + * intptr_t iter = UPB_INTTABLE_BEGIN; + * uintptr_t key; + * upb_value val; + * while (upb_inttable_next2(t, &key, &val, &iter)) { + * // ... + * } + */ -/* Map entries aren't actually stored, they are only used during parsing. For - * parsing, it helps a lot if all map entry messages have the same layout. - * The compiler and def.c must ensure that all map entries have this layout. */ -typedef struct { - upb_Message_Internal internal; - union { - upb_StringView str; /* For str/bytes. */ - upb_value val; /* For all other types. */ - } k; - union { - upb_StringView str; /* For str/bytes. */ - upb_value val; /* For all other types. */ - } v; -} upb_MapEntry; +#define UPB_INTTABLE_BEGIN -1 -/* Creates a new map on the given arena with this key/value type. */ -upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size); +bool upb_inttable_next2(const upb_inttable* t, uintptr_t* key, upb_value* val, + intptr_t* iter); +void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter); -/* Converting between internal table representation and user values. - * - * _upb_map_tokey() and _upb_map_fromkey() are inverses. - * _upb_map_tovalue() and _upb_map_fromvalue() are inverses. +/* Iteration over strtable. * - * These functions account for the fact that strings are treated differently - * from other types when stored in a map. + * intptr_t iter = UPB_INTTABLE_BEGIN; + * upb_StringView key; + * upb_value val; + * while (upb_strtable_next2(t, &key, &val, &iter)) { + * // ... + * } */ -UPB_INLINE upb_StringView _upb_map_tokey(const void* key, size_t size) { - if (size == UPB_MAPTYPE_STRING) { - return *(upb_StringView*)key; - } else { - return upb_StringView_FromDataAndSize((const char*)key, size); - } -} +#define UPB_STRTABLE_BEGIN -1 -UPB_INLINE void _upb_map_fromkey(upb_StringView key, void* out, size_t size) { - if (size == UPB_MAPTYPE_STRING) { - memcpy(out, &key, sizeof(key)); - } else { - memcpy(out, key.data, size); - } -} +bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key, + upb_value* val, intptr_t* iter); +void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter); -UPB_INLINE bool _upb_map_tovalue(const void* val, size_t size, - upb_value* msgval, upb_Arena* a) { - if (size == UPB_MAPTYPE_STRING) { - upb_StringView* strp = (upb_StringView*)upb_Arena_Malloc(a, sizeof(*strp)); - if (!strp) return false; - *strp = *(upb_StringView*)val; - *msgval = upb_value_ptr(strp); - } else { - memcpy(msgval, val, size); - } - return true; -} +/* DEPRECATED iterators, slated for removal. + * + * Iterators for int and string tables. We are subject to some kind of unusual + * design constraints: + * + * For high-level languages: + * - we must be able to guarantee that we don't crash or corrupt memory even if + * the program accesses an invalidated iterator. + * + * For C++11 range-based for: + * - iterators must be copyable + * - iterators must be comparable + * - it must be possible to construct an "end" value. + * + * Iteration order is undefined. + * + * Modifying the table invalidates iterators. upb_{str,int}table_done() is + * guaranteed to work even on an invalidated iterator, as long as the table it + * is iterating over has not been freed. Calling next() or accessing data from + * an invalidated iterator yields unspecified elements from the table, but it is + * guaranteed not to crash and to return real table elements (except when done() + * is true). */ -UPB_INLINE void _upb_map_fromvalue(upb_value val, void* out, size_t size) { - if (size == UPB_MAPTYPE_STRING) { - const upb_StringView* strp = (const upb_StringView*)upb_value_getptr(val); - memcpy(out, strp, sizeof(upb_StringView)); - } else { - memcpy(out, &val, size); - } -} +/* upb_strtable_iter **********************************************************/ -/* Map operations, shared by reflection and generated code. */ +/* upb_strtable_iter i; + * upb_strtable_begin(&i, t); + * for(; !upb_strtable_done(&i); upb_strtable_next(&i)) { + * const char *key = upb_strtable_iter_key(&i); + * const upb_value val = upb_strtable_iter_value(&i); + * // ... + * } + */ -UPB_INLINE size_t _upb_Map_Size(const upb_Map* map) { - return map->table.t.count; -} +typedef struct { + const upb_strtable* t; + size_t index; +} upb_strtable_iter; -UPB_INLINE bool _upb_Map_Get(const upb_Map* map, const void* key, - size_t key_size, void* val, size_t val_size) { - upb_value tabval; - upb_StringView k = _upb_map_tokey(key, key_size); - bool ret = upb_strtable_lookup2(&map->table, k.data, k.size, &tabval); - if (ret && val) { - _upb_map_fromvalue(tabval, val, val_size); - } - return ret; -} +void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t); +void upb_strtable_next(upb_strtable_iter* i); +bool upb_strtable_done(const upb_strtable_iter* i); +upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i); +upb_value upb_strtable_iter_value(const upb_strtable_iter* i); +void upb_strtable_iter_setdone(upb_strtable_iter* i); +bool upb_strtable_iter_isequal(const upb_strtable_iter* i1, + const upb_strtable_iter* i2); -UPB_INLINE void* _upb_map_next(const upb_Map* map, size_t* iter) { - upb_strtable_iter it; - it.t = &map->table; - it.index = *iter; - upb_strtable_next(&it); - *iter = it.index; - if (upb_strtable_done(&it)) return NULL; - return (void*)str_tabent(&it); -} +/* upb_inttable_iter **********************************************************/ -UPB_INLINE bool _upb_Map_Set(upb_Map* map, const void* key, size_t key_size, - void* val, size_t val_size, upb_Arena* a) { - upb_StringView strkey = _upb_map_tokey(key, key_size); - upb_value tabval = {0}; - if (!_upb_map_tovalue(val, val_size, &tabval, a)) return false; +/* upb_inttable_iter i; + * upb_inttable_begin(&i, t); + * for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { + * uintptr_t key = upb_inttable_iter_key(&i); + * upb_value val = upb_inttable_iter_value(&i); + * // ... + * } + */ - /* TODO(haberman): add overwrite operation to minimize number of lookups. */ - upb_strtable_remove2(&map->table, strkey.data, strkey.size, NULL); - return upb_strtable_insert(&map->table, strkey.data, strkey.size, tabval, a); -} +typedef struct { + const upb_inttable* t; + size_t index; + bool array_part; +} upb_inttable_iter; -UPB_INLINE bool _upb_Map_Delete(upb_Map* map, const void* key, - size_t key_size) { - upb_StringView k = _upb_map_tokey(key, key_size); - return upb_strtable_remove2(&map->table, k.data, k.size, NULL); +UPB_INLINE const upb_tabent* str_tabent(const upb_strtable_iter* i) { + return &i->t->t.entries[i->index]; } -UPB_INLINE void _upb_Map_Clear(upb_Map* map) { - upb_strtable_clear(&map->table); -} +void upb_inttable_begin(upb_inttable_iter* i, const upb_inttable* t); +void upb_inttable_next(upb_inttable_iter* i); +bool upb_inttable_done(const upb_inttable_iter* i); +uintptr_t upb_inttable_iter_key(const upb_inttable_iter* i); +upb_value upb_inttable_iter_value(const upb_inttable_iter* i); +void upb_inttable_iter_setdone(upb_inttable_iter* i); +bool upb_inttable_iter_isequal(const upb_inttable_iter* i1, + const upb_inttable_iter* i2); -/* Message map operations, these get the map from the message first. */ +uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed); -UPB_INLINE size_t _upb_msg_map_size(const upb_Message* msg, size_t ofs) { - upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); - return map ? _upb_Map_Size(map) : 0; -} +#ifdef __cplusplus +} /* extern "C" */ +#endif -UPB_INLINE bool _upb_msg_map_get(const upb_Message* msg, size_t ofs, - const void* key, size_t key_size, void* val, - size_t val_size) { - upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); - if (!map) return false; - return _upb_Map_Get(map, key, key_size, val, val_size); -} -UPB_INLINE void* _upb_msg_map_next(const upb_Message* msg, size_t ofs, - size_t* iter) { - upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); - if (!map) return NULL; - return _upb_map_next(map, iter); -} +#endif /* UPB_INTERNAL_TABLE_H_ */ -UPB_INLINE bool _upb_msg_map_set(upb_Message* msg, size_t ofs, const void* key, - size_t key_size, void* val, size_t val_size, - upb_Arena* arena) { - upb_Map** map = UPB_PTR_AT(msg, ofs, upb_Map*); - if (!*map) { - *map = _upb_Map_New(arena, key_size, val_size); - } - return _upb_Map_Set(*map, key, key_size, val, val_size, arena); -} +// Must be last. -UPB_INLINE bool _upb_msg_map_delete(upb_Message* msg, size_t ofs, - const void* key, size_t key_size) { - upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); - if (!map) return false; - return _upb_Map_Delete(map, key, key_size); -} +#ifdef __cplusplus +extern "C" { +#endif -UPB_INLINE void _upb_msg_map_clear(upb_Message* msg, size_t ofs) { - upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); - if (!map) return; - _upb_Map_Clear(map); -} +/** upb_*Int* conversion routines ********************************************/ -/* Accessing map key/value from a pointer, used by generated code only. */ +UPB_INLINE int32_t _upb_Int32_FromI(int v) { return (int32_t)v; } -UPB_INLINE void _upb_msg_map_key(const void* msg, void* key, size_t size) { - const upb_tabent* ent = (const upb_tabent*)msg; - uint32_t u32len; - upb_StringView k; - k.data = upb_tabstr(ent->key, &u32len); - k.size = u32len; - _upb_map_fromkey(k, key, size); -} +UPB_INLINE int64_t _upb_Int64_FromLL(long long v) { return (int64_t)v; } -UPB_INLINE void _upb_msg_map_value(const void* msg, void* val, size_t size) { - const upb_tabent* ent = (const upb_tabent*)msg; - upb_value v = {ent->val.val}; - _upb_map_fromvalue(v, val, size); -} +UPB_INLINE uint32_t _upb_UInt32_FromU(unsigned v) { return (uint32_t)v; } -UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, - size_t size) { - upb_tabent* ent = (upb_tabent*)msg; - /* This is like _upb_map_tovalue() except the entry already exists so we can - * reuse the allocated upb_StringView for string fields. */ - if (size == UPB_MAPTYPE_STRING) { - upb_StringView* strp = (upb_StringView*)(uintptr_t)ent->val.val; - memcpy(strp, val, sizeof(*strp)); - } else { - memcpy(&ent->val.val, val, size); - } +UPB_INLINE uint64_t _upb_UInt64_FromULL(unsigned long long v) { + return (uint64_t)v; } -/** _upb_mapsorter - * *************************************************************/ +extern const float kUpb_FltInfinity; +extern const double kUpb_Infinity; -/* _upb_mapsorter sorts maps and provides ordered iteration over the entries. - * Since maps can be recursive (map values can be messages which contain other - * maps). _upb_mapsorter can contain a stack of maps. */ +/** upb_MiniTable *************************************************************/ -typedef struct { - upb_tabent const** entries; - int size; - int cap; -} _upb_mapsorter; +/* upb_MiniTable represents the memory layout of a given upb_MessageDef. The + * members are public so generated code can initialize them, but users MUST NOT + * read or write any of its members. */ typedef struct { - int start; - int pos; - int end; -} _upb_sortedmap; + uint32_t number; + uint16_t offset; + int16_t presence; // If >0, hasbit_index. If <0, ~oneof_index + uint16_t submsg_index; // kUpb_NoSub if descriptortype != MESSAGE/GROUP/ENUM + uint8_t descriptortype; + uint8_t mode; /* upb_FieldMode | upb_LabelFlags | + (upb_FieldRep << kUpb_FieldRep_Shift) */ +} upb_MiniTable_Field; -UPB_INLINE void _upb_mapsorter_init(_upb_mapsorter* s) { - s->entries = NULL; - s->size = 0; - s->cap = 0; -} +#define kUpb_NoSub ((uint16_t)-1) -UPB_INLINE void _upb_mapsorter_destroy(_upb_mapsorter* s) { - if (s->entries) free(s->entries); -} +typedef enum { + kUpb_FieldMode_Map = 0, + kUpb_FieldMode_Array = 1, + kUpb_FieldMode_Scalar = 2, +} upb_FieldMode; -bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, - const upb_Map* map, _upb_sortedmap* sorted); +// Mask to isolate the upb_FieldMode from field.mode. +#define kUpb_FieldMode_Mask 3 -UPB_INLINE void _upb_mapsorter_popmap(_upb_mapsorter* s, - _upb_sortedmap* sorted) { - s->size = sorted->start; +/* Extra flags on the mode field. */ +typedef enum { + kUpb_LabelFlags_IsPacked = 4, + kUpb_LabelFlags_IsExtension = 8, +} upb_LabelFlags; + +// Note: we sort by this number when calculating layout order. +typedef enum { + kUpb_FieldRep_1Byte = 0, + kUpb_FieldRep_4Byte = 1, + kUpb_FieldRep_StringView = 2, + kUpb_FieldRep_Pointer = 3, + kUpb_FieldRep_8Byte = 4, + + kUpb_FieldRep_Shift = 5, // Bit offset of the rep in upb_MiniTable_Field.mode + kUpb_FieldRep_Max = kUpb_FieldRep_8Byte, +} upb_FieldRep; + +UPB_INLINE upb_FieldMode upb_FieldMode_Get(const upb_MiniTable_Field* field) { + return (upb_FieldMode)(field->mode & 3); } -UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter* s, const upb_Map* map, - _upb_sortedmap* sorted, upb_MapEntry* ent) { - if (sorted->pos == sorted->end) return false; - const upb_tabent* tabent = s->entries[sorted->pos++]; - upb_StringView key = upb_tabstrview(tabent->key); - _upb_map_fromkey(key, &ent->k, map->key_size); - upb_value val = {tabent->val.val}; - _upb_map_fromvalue(val, &ent->v, map->val_size); - return true; +UPB_INLINE bool upb_IsRepeatedOrMap(const upb_MiniTable_Field* field) { + /* This works because upb_FieldMode has no value 3. */ + return !(field->mode & kUpb_FieldMode_Scalar); } -#ifdef __cplusplus -} /* extern "C" */ -#endif +UPB_INLINE bool upb_IsSubMessage(const upb_MiniTable_Field* field) { + return field->descriptortype == kUpb_FieldType_Message || + field->descriptortype == kUpb_FieldType_Group; +} +struct upb_Decoder; +struct upb_MiniTable; -#endif /* UPB_MSG_INT_H_ */ +typedef const char* _upb_FieldParser(struct upb_Decoder* d, const char* ptr, + upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t data); -/** upb/upb_internal.h ************************************************************/ -#ifndef UPB_INT_H_ -#define UPB_INT_H_ +typedef struct { + uint64_t field_data; + _upb_FieldParser* field_parser; +} _upb_FastTable_Entry; +typedef struct { + uint32_t mask_limit; // Limit enum value that can be tested with mask. + uint32_t value_count; // Number of values after the bitfield. + uint32_t data[]; // Bitmask + enumerated values follow. +} upb_MiniTable_Enum; -struct mem_block; -typedef struct mem_block mem_block; +typedef enum { + _kUpb_FastEnumCheck_ValueIsInEnum = 0, + _kUpb_FastEnumCheck_ValueIsNotInEnum = 1, + _kUpb_FastEnumCheck_CannotCheckFast = 2, +} _kUpb_FastEnumCheck_Status; + +UPB_INLINE _kUpb_FastEnumCheck_Status +_upb_MiniTable_CheckEnumValueFast(const upb_MiniTable_Enum* e, uint32_t val) { + if (UPB_UNLIKELY(val >= 64)) return _kUpb_FastEnumCheck_CannotCheckFast; + uint64_t mask = e->data[0] | ((uint64_t)e->data[1] << 32); + return (mask & (1ULL << val)) ? _kUpb_FastEnumCheck_ValueIsInEnum + : _kUpb_FastEnumCheck_ValueIsNotInEnum; +} + +UPB_INLINE bool _upb_MiniTable_CheckEnumValueSlow(const upb_MiniTable_Enum* e, + uint32_t val) { + if (val < e->mask_limit) return e->data[val / 32] & (1ULL << (val % 32)); + // OPT: binary search long lists? + const uint32_t* start = &e->data[e->mask_limit / 32]; + const uint32_t* limit = &e->data[(e->mask_limit / 32) + e->value_count]; + for (const uint32_t* p = start; p < limit; p++) { + if (*p == val) return true; + } + return false; +} -struct upb_Arena { - _upb_ArenaHead head; - /* Stores cleanup metadata for this arena. - * - a pointer to the current cleanup counter. - * - a boolean indicating if there is an unowned initial block. */ - uintptr_t cleanup_metadata; +// Validates enum value against range defined by enum mini table. +UPB_INLINE bool upb_MiniTable_Enum_CheckValue(const upb_MiniTable_Enum* e, + uint32_t val) { + _kUpb_FastEnumCheck_Status status = _upb_MiniTable_CheckEnumValueFast(e, val); + if (UPB_UNLIKELY(status == _kUpb_FastEnumCheck_CannotCheckFast)) { + return _upb_MiniTable_CheckEnumValueSlow(e, val); + } + return status == _kUpb_FastEnumCheck_ValueIsInEnum ? true : false; +} - /* Allocator to allocate arena blocks. We are responsible for freeing these - * when we are destroyed. */ - upb_alloc* block_alloc; - uint32_t last_size; +typedef union { + const struct upb_MiniTable* submsg; + const upb_MiniTable_Enum* subenum; +} upb_MiniTable_Sub; - /* When multiple arenas are fused together, each arena points to a parent - * arena (root points to itself). The root tracks how many live arenas - * reference it. */ - uint32_t refcount; /* Only used when a->parent == a */ - struct upb_Arena* parent; +typedef enum { + kUpb_ExtMode_NonExtendable = 0, // Non-extendable message. + kUpb_ExtMode_Extendable = 1, // Normal extendable message. + kUpb_ExtMode_IsMessageSet = 2, // MessageSet message. + kUpb_ExtMode_IsMessageSet_ITEM = + 3, // MessageSet item (temporary only, see decode.c) - /* Linked list of blocks to free/cleanup. */ - mem_block *freelist, *freelist_tail; + // During table building we steal a bit to indicate that the message is a map + // entry. *Only* used during table building! + kUpb_ExtMode_IsMapEntry = 4, +} upb_ExtMode; + +/* MessageSet wire format is: + * message MessageSet { + * repeated group Item = 1 { + * required int32 type_id = 2; + * required bytes message = 3; + * } + * } + */ +typedef enum { + _UPB_MSGSET_ITEM = 1, + _UPB_MSGSET_TYPEID = 2, + _UPB_MSGSET_MESSAGE = 3, +} upb_msgext_fieldnum; + +struct upb_MiniTable { + const upb_MiniTable_Sub* subs; + const upb_MiniTable_Field* fields; + /* Must be aligned to sizeof(void*). Doesn't include internal members like + * unknown fields, extension dict, pointer to msglayout, etc. */ + uint16_t size; + uint16_t field_count; + uint8_t ext; // upb_ExtMode, declared as uint8_t so sizeof(ext) == 1 + uint8_t dense_below; + uint8_t table_mask; + uint8_t required_count; // Required fields have the lowest hasbits. + /* To statically initialize the tables of variable length, we need a flexible + * array member, and we need to compile in gnu99 mode (constant initialization + * of flexible array members is a GNU extension, not in C99 unfortunately. */ + _upb_FastTable_Entry fasttable[]; }; -// Encodes a float or double that is round-trippable, but as short as possible. -// These routines are not fully optimal (not guaranteed to be shortest), but are -// short-ish and match the implementation that has been used in protobuf since -// the beginning. +typedef struct upb_MiniTable_Extension upb_MiniTable_Extension; + +struct upb_MiniTable_Extension { + upb_MiniTable_Field field; + const upb_MiniTable* extendee; + upb_MiniTable_Sub sub; /* NULL unless submessage or proto2 enum */ +}; + +typedef struct { + const upb_MiniTable** msgs; + const upb_MiniTable_Enum** enums; + const upb_MiniTable_Extension** exts; + int msg_count; + int enum_count; + int ext_count; +} upb_MiniTable_File; + +// Computes a bitmask in which the |l->required_count| lowest bits are set, +// except that we skip the lowest bit (because upb never uses hasbit 0). // -// The given buffer size must be at least kUpb_RoundTripBufferSize. -enum { kUpb_RoundTripBufferSize = 32 }; -void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size); -void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size); +// Sample output: +// requiredmask(1) => 0b10 (0x2) +// requiredmask(5) => 0b111110 (0x3e) +UPB_INLINE uint64_t upb_MiniTable_requiredmask(const upb_MiniTable* l) { + int n = l->required_count; + assert(0 < n && n <= 63); + return ((1ULL << n) - 1) << 1; +} -#endif /* UPB_INT_H_ */ +/** upb_Message ***************************************************************/ -/* Must be last. */ +/* Internal members of a upb_Message that track unknown fields and/or + * extensions. We can change this without breaking binary compatibility. We put + * these before the user's data. The user's upb_Message* points after the + * upb_Message_Internal. */ -#define DECODE_NOGROUP (uint32_t) - 1 +typedef struct { + /* Total size of this structure, including the data that follows. + * Must be aligned to 8, which is alignof(upb_Message_Extension) */ + uint32_t size; -typedef struct upb_Decoder { - const char* end; /* Can read up to 16 bytes slop beyond this. */ - const char* limit_ptr; /* = end + UPB_MIN(limit, 0) */ - upb_Message* unknown_msg; /* If non-NULL, add unknown data at buffer flip. */ - const char* unknown; /* Start of unknown data. */ - const upb_ExtensionRegistry* - extreg; /* For looking up extensions during the parse. */ - int limit; /* Submessage limit relative to end. */ - int depth; /* Tracks recursion depth to bound stack usage. */ - uint32_t end_group; /* field number of END_GROUP tag, else DECODE_NOGROUP */ - uint16_t options; - bool missing_required; - char patch[32]; - upb_Arena arena; - jmp_buf err; + /* Offsets relative to the beginning of this structure. + * + * Unknown data grows forward from the beginning to unknown_end. + * Extension data grows backward from size to ext_begin. + * When the two meet, we're out of data and have to realloc. + * + * If we imagine that the final member of this struct is: + * char data[size - overhead]; // overhead = + * sizeof(upb_Message_InternalData) + * + * Then we have: + * unknown data: data[0 .. (unknown_end - overhead)] + * extensions data: data[(ext_begin - overhead) .. (size - overhead)] */ + uint32_t unknown_end; + uint32_t ext_begin; + /* Data follows, as if there were an array: + * char data[size - sizeof(upb_Message_InternalData)]; */ +} upb_Message_InternalData; -#ifndef NDEBUG - const char* debug_tagstart; - const char* debug_valstart; -#endif -} upb_Decoder; +typedef struct { + upb_Message_InternalData* internal; + /* Message data follows. */ +} upb_Message_Internal; -/* Error function that will abort decoding with longjmp(). We can't declare this - * UPB_NORETURN, even though it is appropriate, because if we do then compilers - * will "helpfully" refuse to tailcall to it - * (see: https://stackoverflow.com/a/55657013), which will defeat a major goal - * of our optimizations. That is also why we must declare it in a separate file, - * otherwise the compiler will see that it calls longjmp() and deduce that it is - * noreturn. */ -const char* fastdecode_err(upb_Decoder* d, int status); +/* Maps upb_CType -> memory size. */ +extern char _upb_CTypeo_size[12]; -extern const uint8_t upb_utf8_offsets[]; +UPB_INLINE size_t upb_msg_sizeof(const upb_MiniTable* l) { + return l->size + sizeof(upb_Message_Internal); +} -UPB_INLINE -bool decode_verifyutf8_inl(const char* ptr, int len) { - const char* end = ptr + len; +UPB_INLINE upb_Message* _upb_Message_New_inl(const upb_MiniTable* l, + upb_Arena* a) { + size_t size = upb_msg_sizeof(l); + void* mem = upb_Arena_Malloc(a, size + sizeof(upb_Message_Internal)); + upb_Message* msg; + if (UPB_UNLIKELY(!mem)) return NULL; + msg = UPB_PTR_AT(mem, sizeof(upb_Message_Internal), upb_Message); + memset(mem, 0, size); + return msg; +} - // Check 8 bytes at a time for any non-ASCII char. - while (end - ptr >= 8) { - uint64_t data; - memcpy(&data, ptr, 8); - if (data & 0x8080808080808080) goto non_ascii; - ptr += 8; - } +/* Creates a new messages with the given layout on the given arena. */ +upb_Message* _upb_Message_New(const upb_MiniTable* l, upb_Arena* a); - // Check one byte at a time for non-ASCII. - while (ptr < end) { - if (*ptr & 0x80) goto non_ascii; - ptr++; - } +UPB_INLINE upb_Message_Internal* upb_Message_Getinternal(upb_Message* msg) { + ptrdiff_t size = sizeof(upb_Message_Internal); + return (upb_Message_Internal*)((char*)msg - size); +} - return true; +/* Clears the given message. */ +void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l); -non_ascii: - return utf8_range2((const unsigned char*)ptr, end - ptr) == 0; -} +/* Discards the unknown fields for this message only. */ +void _upb_Message_DiscardUnknown_shallow(upb_Message* msg); -const char* decode_checkrequired(upb_Decoder* d, const char* ptr, - const upb_Message* msg, - const upb_MiniTable* l); +/* Adds unknown data (serialized protobuf data) to the given message. The data + * is copied into the message instance. */ +bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, + upb_Arena* arena); -/* x86-64 pointers always have the high 16 bits matching. So we can shift - * left 8 and right 8 without loss of information. */ -UPB_INLINE intptr_t decode_totable(const upb_MiniTable* tablep) { - return ((intptr_t)tablep << 8) | tablep->table_mask; -} +/** upb_Message_Extension *****************************************************/ -UPB_INLINE const upb_MiniTable* decode_totablep(intptr_t table) { - return (const upb_MiniTable*)(table >> 8); -} +/* The internal representation of an extension is self-describing: it contains + * enough information that we can serialize it to binary format without needing + * to look it up in a upb_ExtensionRegistry. + * + * This representation allocates 16 bytes to data on 64-bit platforms. This is + * rather wasteful for scalars (in the extreme case of bool, it wastes 15 + * bytes). We accept this because we expect messages to be the most common + * extension type. */ +typedef struct { + const upb_MiniTable_Extension* ext; + union { + upb_StringView str; + void* ptr; + char scalar_data[8]; + } data; +} upb_Message_Extension; -UPB_INLINE -const char* decode_isdonefallback_inl(upb_Decoder* d, const char* ptr, - int overrun, int* status) { - if (overrun < d->limit) { - /* Need to copy remaining data into patch buffer. */ - UPB_ASSERT(overrun < 16); - if (d->unknown_msg) { - if (!_upb_Message_AddUnknown(d->unknown_msg, d->unknown, ptr - d->unknown, - &d->arena)) { - *status = kUpb_DecodeStatus_OutOfMemory; - return NULL; - } - d->unknown = &d->patch[0] + overrun; - } - memset(d->patch + 16, 0, 16); - memcpy(d->patch, d->end, 16); - ptr = &d->patch[0] + overrun; - d->end = &d->patch[16]; - d->limit -= 16; - d->limit_ptr = d->end + d->limit; - d->options &= ~kUpb_DecodeOption_AliasString; - UPB_ASSERT(ptr < d->limit_ptr); - return ptr; - } else { - *status = kUpb_DecodeStatus_Malformed; - return NULL; - } -} +/* Adds the given extension data to the given message. |ext| is copied into the + * message instance. This logically replaces any previously-added extension with + * this number */ +upb_Message_Extension* _upb_Message_GetOrCreateExtension( + upb_Message* msg, const upb_MiniTable_Extension* ext, upb_Arena* arena); -const char* decode_isdonefallback(upb_Decoder* d, const char* ptr, int overrun); +/* Returns an array of extensions for this message. Note: the array is + * ordered in reverse relative to the order of creation. */ +const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg, + size_t* count); -UPB_INLINE -bool decode_isdone(upb_Decoder* d, const char** ptr) { - int overrun = *ptr - d->end; - if (UPB_LIKELY(*ptr < d->limit_ptr)) { - return false; - } else if (UPB_LIKELY(overrun == d->limit)) { - return true; - } else { - *ptr = decode_isdonefallback(d, *ptr, overrun); - return false; - } -} +/* Returns an extension for the given field number, or NULL if no extension + * exists for this field number. */ +const upb_Message_Extension* _upb_Message_Getext( + const upb_Message* msg, const upb_MiniTable_Extension* ext); -#if UPB_FASTTABLE -UPB_INLINE -const char* fastdecode_tagdispatch(upb_Decoder* d, const char* ptr, - upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t tag) { - const upb_MiniTable* table_p = decode_totablep(table); - uint8_t mask = table; - uint64_t data; - size_t idx = tag & mask; - UPB_ASSUME((idx & 7) == 0); - idx >>= 3; - data = table_p->fasttable[idx].field_data ^ tag; - UPB_MUSTTAIL return table_p->fasttable[idx].field_parser(d, ptr, msg, table, - hasbits, data); -} -#endif +void _upb_Message_Clearext(upb_Message* msg, + const upb_MiniTable_Extension* ext); -UPB_INLINE uint32_t fastdecode_loadtag(const char* ptr) { - uint16_t tag; - memcpy(&tag, ptr, 2); - return tag; +void _upb_Message_Clearext(upb_Message* msg, + const upb_MiniTable_Extension* ext); + +/** Hasbit access *************************************************************/ + +UPB_INLINE bool _upb_hasbit(const upb_Message* msg, size_t idx) { + return (*UPB_PTR_AT(msg, idx / 8, const char) & (1 << (idx % 8))) != 0; } -UPB_INLINE void decode_checklimit(upb_Decoder* d) { - UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); +UPB_INLINE void _upb_sethas(const upb_Message* msg, size_t idx) { + (*UPB_PTR_AT(msg, idx / 8, char)) |= (char)(1 << (idx % 8)); } -UPB_INLINE int decode_pushlimit(upb_Decoder* d, const char* ptr, int size) { - int limit = size + (int)(ptr - d->end); - int delta = d->limit - limit; - decode_checklimit(d); - d->limit = limit; - d->limit_ptr = d->end + UPB_MIN(0, limit); - decode_checklimit(d); - return delta; +UPB_INLINE void _upb_clearhas(const upb_Message* msg, size_t idx) { + (*UPB_PTR_AT(msg, idx / 8, char)) &= (char)(~(1 << (idx % 8))); } -UPB_INLINE void decode_poplimit(upb_Decoder* d, const char* ptr, - int saved_delta) { - UPB_ASSERT(ptr - d->end == d->limit); - decode_checklimit(d); - d->limit += saved_delta; - d->limit_ptr = d->end + UPB_MIN(0, d->limit); - decode_checklimit(d); +UPB_INLINE size_t _upb_Message_Hasidx(const upb_MiniTable_Field* f) { + UPB_ASSERT(f->presence > 0); + return f->presence; } +UPB_INLINE bool _upb_hasbit_field(const upb_Message* msg, + const upb_MiniTable_Field* f) { + return _upb_hasbit(msg, _upb_Message_Hasidx(f)); +} -#endif /* UPB_DECODE_INT_H_ */ +UPB_INLINE void _upb_sethas_field(const upb_Message* msg, + const upb_MiniTable_Field* f) { + _upb_sethas(msg, _upb_Message_Hasidx(f)); +} -/** upb/encode.h ************************************************************/ -/* - * upb_Encode: parsing into a upb_Message using a upb_MiniTable. - */ +UPB_INLINE void _upb_clearhas_field(const upb_Message* msg, + const upb_MiniTable_Field* f) { + _upb_clearhas(msg, _upb_Message_Hasidx(f)); +} -#ifndef UPB_ENCODE_H_ -#define UPB_ENCODE_H_ +/** Oneof case access *********************************************************/ +UPB_INLINE uint32_t* _upb_oneofcase(upb_Message* msg, size_t case_ofs) { + return UPB_PTR_AT(msg, case_ofs, uint32_t); +} -/* Must be last. */ +UPB_INLINE uint32_t _upb_getoneofcase(const void* msg, size_t case_ofs) { + return *UPB_PTR_AT(msg, case_ofs, uint32_t); +} -#ifdef __cplusplus -extern "C" { -#endif +UPB_INLINE size_t _upb_oneofcase_ofs(const upb_MiniTable_Field* f) { + UPB_ASSERT(f->presence < 0); + return ~(ptrdiff_t)f->presence; +} -enum { - /* If set, the results of serializing will be deterministic across all - * instances of this binary. There are no guarantees across different - * binary builds. - * - * If your proto contains maps, the encoder will need to malloc()/free() - * memory during encode. */ - kUpb_Encode_Deterministic = 1, +UPB_INLINE uint32_t* _upb_oneofcase_field(upb_Message* msg, + const upb_MiniTable_Field* f) { + return _upb_oneofcase(msg, _upb_oneofcase_ofs(f)); +} - /* When set, unknown fields are not printed. */ - kUpb_Encode_SkipUnknown = 2, +UPB_INLINE uint32_t _upb_getoneofcase_field(const upb_Message* msg, + const upb_MiniTable_Field* f) { + return _upb_getoneofcase(msg, _upb_oneofcase_ofs(f)); +} - /* When set, the encode will fail if any required fields are missing. */ - kUpb_Encode_CheckRequired = 4, -}; +UPB_INLINE bool _upb_has_submsg_nohasbit(const upb_Message* msg, size_t ofs) { + return *UPB_PTR_AT(msg, ofs, const upb_Message*) != NULL; +} -#define UPB_ENCODE_MAXDEPTH(depth) ((depth) << 16) - -char* upb_Encode(const void* msg, const upb_MiniTable* l, int options, - upb_Arena* arena, size_t* size); +/** upb_Map *******************************************************************/ +/* Right now we use strmaps for everything. We'll likely want to use + * integer-specific maps for integer-keyed maps.*/ +struct upb_Map { + /* Size of key and val, based on the map type. Strings are represented as '0' + * because they must be handled specially. */ + char key_size; + char val_size; -#ifdef __cplusplus -} /* extern "C" */ -#endif + upb_strtable table; +}; -#endif /* UPB_ENCODE_H_ */ +/* Map entries aren't actually stored, they are only used during parsing. For + * parsing, it helps a lot if all map entry messages have the same layout. + * The compiler and def.c must ensure that all map entries have this layout. */ +typedef struct { + upb_Message_Internal internal; + union { + upb_StringView str; /* For str/bytes. */ + upb_value val; /* For all other types. */ + } k; + union { + upb_StringView str; /* For str/bytes. */ + upb_value val; /* For all other types. */ + } v; +} upb_MapEntry; -/** upb/decode_fast.h ************************************************************/ -// These are the specialized field parser functions for the fast parser. -// Generated tables will refer to these by name. -// -// The function names are encoded with names like: -// -// // 123 4 -// upb_pss_1bt(); // Parse singular string, 1 byte tag. -// -// In position 1: -// - 'p' for parse, most function use this -// - 'c' for copy, for when we are copying strings instead of aliasing -// -// In position 2 (cardinality): -// - 's' for singular, with or without hasbit -// - 'o' for oneof -// - 'r' for non-packed repeated -// - 'p' for packed repeated -// -// In position 3 (type): -// - 'b1' for bool -// - 'v4' for 4-byte varint -// - 'v8' for 8-byte varint -// - 'z4' for zig-zag-encoded 4-byte varint -// - 'z8' for zig-zag-encoded 8-byte varint -// - 'f4' for 4-byte fixed -// - 'f8' for 8-byte fixed -// - 'm' for sub-message -// - 's' for string (validate UTF-8) -// - 'b' for bytes -// -// In position 4 (tag length): -// - '1' for one-byte tags (field numbers 1-15) -// - '2' for two-byte tags (field numbers 16-2048) +/* Creates a new map on the given arena with this key/value type. */ +upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size); -#ifndef UPB_DECODE_FAST_H_ -#define UPB_DECODE_FAST_H_ +/* Converting between internal table representation and user values. + * + * _upb_map_tokey() and _upb_map_fromkey() are inverses. + * _upb_map_tovalue() and _upb_map_fromvalue() are inverses. + * + * These functions account for the fact that strings are treated differently + * from other types when stored in a map. + */ +UPB_INLINE upb_StringView _upb_map_tokey(const void* key, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + return *(upb_StringView*)key; + } else { + return upb_StringView_FromDataAndSize((const char*)key, size); + } +} -struct upb_Decoder; +UPB_INLINE void _upb_map_fromkey(upb_StringView key, void* out, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + memcpy(out, &key, sizeof(key)); + } else { + memcpy(out, key.data, size); + } +} -// The fallback, generic parsing function that can handle any field type. -// This just uses the regular (non-fast) parser to parse a single field. -const char* fastdecode_generic(struct upb_Decoder* d, const char* ptr, - upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t data); +UPB_INLINE bool _upb_map_tovalue(const void* val, size_t size, + upb_value* msgval, upb_Arena* a) { + if (size == UPB_MAPTYPE_STRING) { + upb_StringView* strp = (upb_StringView*)upb_Arena_Malloc(a, sizeof(*strp)); + if (!strp) return false; + *strp = *(upb_StringView*)val; + *msgval = upb_value_ptr(strp); + } else { + memcpy(msgval, val, size); + } + return true; +} -#define UPB_PARSE_PARAMS \ - struct upb_Decoder *d, const char *ptr, upb_Message *msg, intptr_t table, \ - uint64_t hasbits, uint64_t data +UPB_INLINE void _upb_map_fromvalue(upb_value val, void* out, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + const upb_StringView* strp = (const upb_StringView*)upb_value_getptr(val); + memcpy(out, strp, sizeof(upb_StringView)); + } else { + memcpy(out, &val, size); + } +} -/* primitive fields ***********************************************************/ +/* Map operations, shared by reflection and generated code. */ -#define F(card, type, valbytes, tagbytes) \ - const char* upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS); +UPB_INLINE size_t _upb_Map_Size(const upb_Map* map) { + return map->table.t.count; +} -#define TYPES(card, tagbytes) \ - F(card, b, 1, tagbytes) \ - F(card, v, 4, tagbytes) \ - F(card, v, 8, tagbytes) \ - F(card, z, 4, tagbytes) \ - F(card, z, 8, tagbytes) \ - F(card, f, 4, tagbytes) \ - F(card, f, 8, tagbytes) +UPB_INLINE bool _upb_Map_Get(const upb_Map* map, const void* key, + size_t key_size, void* val, size_t val_size) { + upb_value tabval; + upb_StringView k = _upb_map_tokey(key, key_size); + bool ret = upb_strtable_lookup2(&map->table, k.data, k.size, &tabval); + if (ret && val) { + _upb_map_fromvalue(tabval, val, val_size); + } + return ret; +} -#define TAGBYTES(card) \ - TYPES(card, 1) \ - TYPES(card, 2) +UPB_INLINE void* _upb_map_next(const upb_Map* map, size_t* iter) { + upb_strtable_iter it; + it.t = &map->table; + it.index = *iter; + upb_strtable_next(&it); + *iter = it.index; + if (upb_strtable_done(&it)) return NULL; + return (void*)str_tabent(&it); +} -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) -TAGBYTES(p) +typedef enum { + // LINT.IfChange + _kUpb_MapInsertStatus_Inserted = 0, + _kUpb_MapInsertStatus_Replaced = 1, + _kUpb_MapInsertStatus_OutOfMemory = 2, + // LINT.ThenChange(//depot/google3/third_party/upb/upb/map.h) +} _upb_MapInsertStatus; + +UPB_INLINE _upb_MapInsertStatus _upb_Map_Insert(upb_Map* map, const void* key, + size_t key_size, void* val, + size_t val_size, upb_Arena* a) { + upb_StringView strkey = _upb_map_tokey(key, key_size); + upb_value tabval = {0}; + if (!_upb_map_tovalue(val, val_size, &tabval, a)) { + return _kUpb_MapInsertStatus_OutOfMemory; + } -#undef F -#undef TYPES -#undef TAGBYTES + /* TODO(haberman): add overwrite operation to minimize number of lookups. */ + bool removed = + upb_strtable_remove2(&map->table, strkey.data, strkey.size, NULL); + if (!upb_strtable_insert(&map->table, strkey.data, strkey.size, tabval, a)) { + return _kUpb_MapInsertStatus_OutOfMemory; + } + return removed ? _kUpb_MapInsertStatus_Replaced + : _kUpb_MapInsertStatus_Inserted; +} -/* string fields **************************************************************/ +UPB_INLINE bool _upb_Map_Delete(upb_Map* map, const void* key, + size_t key_size) { + upb_StringView k = _upb_map_tokey(key, key_size); + return upb_strtable_remove2(&map->table, k.data, k.size, NULL); +} -#define F(card, tagbytes, type) \ - const char* upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS); \ - const char* upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS); +UPB_INLINE void _upb_Map_Clear(upb_Map* map) { + upb_strtable_clear(&map->table); +} -#define UTF8(card, tagbytes) \ - F(card, tagbytes, s) \ - F(card, tagbytes, b) +/* Message map operations, these get the map from the message first. */ -#define TAGBYTES(card) \ - UTF8(card, 1) \ - UTF8(card, 2) +UPB_INLINE size_t _upb_msg_map_size(const upb_Message* msg, size_t ofs) { + upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); + return map ? _upb_Map_Size(map) : 0; +} -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) +UPB_INLINE bool _upb_msg_map_get(const upb_Message* msg, size_t ofs, + const void* key, size_t key_size, void* val, + size_t val_size) { + upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); + if (!map) return false; + return _upb_Map_Get(map, key, key_size, val, val_size); +} -#undef F -#undef TAGBYTES +UPB_INLINE void* _upb_msg_map_next(const upb_Message* msg, size_t ofs, + size_t* iter) { + upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); + if (!map) return NULL; + return _upb_map_next(map, iter); +} -/* sub-message fields *********************************************************/ +UPB_INLINE bool _upb_msg_map_set(upb_Message* msg, size_t ofs, const void* key, + size_t key_size, void* val, size_t val_size, + upb_Arena* arena) { + upb_Map** map = UPB_PTR_AT(msg, ofs, upb_Map*); + if (!*map) { + *map = _upb_Map_New(arena, key_size, val_size); + } + return _upb_Map_Insert(*map, key, key_size, val, val_size, arena) != + _kUpb_MapInsertStatus_OutOfMemory; +} -#define F(card, tagbytes, size_ceil, ceil_arg) \ - const char* upb_p##card##m_##tagbytes##bt_max##size_ceil##b(UPB_PARSE_PARAMS); +UPB_INLINE bool _upb_msg_map_delete(upb_Message* msg, size_t ofs, + const void* key, size_t key_size) { + upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); + if (!map) return false; + return _upb_Map_Delete(map, key, key_size); +} -#define SIZES(card, tagbytes) \ - F(card, tagbytes, 64, 64) \ - F(card, tagbytes, 128, 128) \ - F(card, tagbytes, 192, 192) \ - F(card, tagbytes, 256, 256) \ - F(card, tagbytes, max, -1) +UPB_INLINE void _upb_msg_map_clear(upb_Message* msg, size_t ofs) { + upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); + if (!map) return; + _upb_Map_Clear(map); +} -#define TAGBYTES(card) \ - SIZES(card, 1) \ - SIZES(card, 2) +/* Accessing map key/value from a pointer, used by generated code only. */ -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) +UPB_INLINE void _upb_msg_map_key(const void* msg, void* key, size_t size) { + const upb_tabent* ent = (const upb_tabent*)msg; + uint32_t u32len; + upb_StringView k; + k.data = upb_tabstr(ent->key, &u32len); + k.size = u32len; + _upb_map_fromkey(k, key, size); +} -#undef TAGBYTES -#undef SIZES -#undef F +UPB_INLINE void _upb_msg_map_value(const void* msg, void* val, size_t size) { + const upb_tabent* ent = (const upb_tabent*)msg; + upb_value v = {ent->val.val}; + _upb_map_fromvalue(v, val, size); +} -#undef UPB_PARSE_PARAMS +UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, + size_t size) { + upb_tabent* ent = (upb_tabent*)msg; + /* This is like _upb_map_tovalue() except the entry already exists so we can + * reuse the allocated upb_StringView for string fields. */ + if (size == UPB_MAPTYPE_STRING) { + upb_StringView* strp = (upb_StringView*)(uintptr_t)ent->val.val; + memcpy(strp, val, sizeof(*strp)); + } else { + memcpy(&ent->val.val, val, size); + } +} -#endif /* UPB_DECODE_FAST_H_ */ +#ifdef __cplusplus +} /* extern "C" */ +#endif -/** google/protobuf/descriptor.upb.h ************************************************************//* This file was generated by upbc (the upb compiler) from the input + +#endif /* UPB_MSG_INT_H_ */ +/* This file was generated by upbc (the upb compiler) from the input * file: * * google/protobuf/descriptor.proto @@ -2284,38 +2179,266 @@ TAGBYTES(r) #define GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ +/* + * upb_decode: parsing into a upb_Message using a upb_MiniTable. + */ + +#ifndef UPB_DECODE_H_ +#define UPB_DECODE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* If set, strings will alias the input buffer instead of copying into the + * arena. */ + kUpb_DecodeOption_AliasString = 1, + + /* If set, the parse will return failure if any message is missing any + * required fields when the message data ends. The parse will still continue, + * and the failure will only be reported at the end. + * + * IMPORTANT CAVEATS: + * + * 1. This can throw a false positive failure if an incomplete message is seen + * on the wire but is later completed when the sub-message occurs again. + * For this reason, a second pass is required to verify a failure, to be + * truly robust. + * + * 2. This can return a false success if you are decoding into a message that + * already has some sub-message fields present. If the sub-message does + * not occur in the binary payload, we will never visit it and discover the + * incomplete sub-message. For this reason, this check is only useful for + * implemting ParseFromString() semantics. For MergeFromString(), a + * post-parse validation step will always be necessary. */ + kUpb_DecodeOption_CheckRequired = 2, +}; + +#define UPB_DECODE_MAXDEPTH(depth) ((depth) << 16) + +typedef enum { + kUpb_DecodeStatus_Ok = 0, + kUpb_DecodeStatus_Malformed = 1, // Wire format was corrupt + kUpb_DecodeStatus_OutOfMemory = 2, // Arena alloc failed + kUpb_DecodeStatus_BadUtf8 = 3, // String field had bad UTF-8 + kUpb_DecodeStatus_MaxDepthExceeded = 4, // Exceeded UPB_DECODE_MAXDEPTH + + // kUpb_DecodeOption_CheckRequired failed (see above), but the parse otherwise + // succeeded. + kUpb_DecodeStatus_MissingRequired = 5, +} upb_DecodeStatus; + +upb_DecodeStatus upb_Decode(const char* buf, size_t size, upb_Message* msg, + const upb_MiniTable* l, + const upb_ExtensionRegistry* extreg, int options, + upb_Arena* arena); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_DECODE_H_ */ + +// These are the specialized field parser functions for the fast parser. +// Generated tables will refer to these by name. +// +// The function names are encoded with names like: +// +// // 123 4 +// upb_pss_1bt(); // Parse singular string, 1 byte tag. +// +// In position 1: +// - 'p' for parse, most function use this +// - 'c' for copy, for when we are copying strings instead of aliasing +// +// In position 2 (cardinality): +// - 's' for singular, with or without hasbit +// - 'o' for oneof +// - 'r' for non-packed repeated +// - 'p' for packed repeated +// +// In position 3 (type): +// - 'b1' for bool +// - 'v4' for 4-byte varint +// - 'v8' for 8-byte varint +// - 'z4' for zig-zag-encoded 4-byte varint +// - 'z8' for zig-zag-encoded 8-byte varint +// - 'f4' for 4-byte fixed +// - 'f8' for 8-byte fixed +// - 'm' for sub-message +// - 's' for string (validate UTF-8) +// - 'b' for bytes +// +// In position 4 (tag length): +// - '1' for one-byte tags (field numbers 1-15) +// - '2' for two-byte tags (field numbers 16-2048) + +#ifndef UPB_DECODE_FAST_H_ +#define UPB_DECODE_FAST_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +struct upb_Decoder; + +// The fallback, generic parsing function that can handle any field type. +// This just uses the regular (non-fast) parser to parse a single field. +const char* _upb_FastDecoder_DecodeGeneric(struct upb_Decoder* d, + const char* ptr, upb_Message* msg, + intptr_t table, uint64_t hasbits, + uint64_t data); + +#define UPB_PARSE_PARAMS \ + struct upb_Decoder *d, const char *ptr, upb_Message *msg, intptr_t table, \ + uint64_t hasbits, uint64_t data + +/* primitive fields ***********************************************************/ + +#define F(card, type, valbytes, tagbytes) \ + const char* upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS); + +#define TYPES(card, tagbytes) \ + F(card, b, 1, tagbytes) \ + F(card, v, 4, tagbytes) \ + F(card, v, 8, tagbytes) \ + F(card, z, 4, tagbytes) \ + F(card, z, 8, tagbytes) \ + F(card, f, 4, tagbytes) \ + F(card, f, 8, tagbytes) + +#define TAGBYTES(card) \ + TYPES(card, 1) \ + TYPES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) +TAGBYTES(p) + +#undef F +#undef TYPES +#undef TAGBYTES + +/* string fields **************************************************************/ + +#define F(card, tagbytes, type) \ + const char* upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS); \ + const char* upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS); + +#define UTF8(card, tagbytes) \ + F(card, tagbytes, s) \ + F(card, tagbytes, b) + +#define TAGBYTES(card) \ + UTF8(card, 1) \ + UTF8(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) + +#undef F +#undef TAGBYTES + +/* sub-message fields *********************************************************/ + +#define F(card, tagbytes, size_ceil, ceil_arg) \ + const char* upb_p##card##m_##tagbytes##bt_max##size_ceil##b(UPB_PARSE_PARAMS); + +#define SIZES(card, tagbytes) \ + F(card, tagbytes, 64, 64) \ + F(card, tagbytes, 128, 128) \ + F(card, tagbytes, 192, 192) \ + F(card, tagbytes, 256, 256) \ + F(card, tagbytes, max, -1) + +#define TAGBYTES(card) \ + SIZES(card, 1) \ + SIZES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) + +#undef TAGBYTES +#undef SIZES +#undef F + +#undef UPB_PARSE_PARAMS + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_DECODE_FAST_H_ */ + +/* + * upb_Encode: parsing from a upb_Message using a upb_MiniTable. + */ + +#ifndef UPB_ENCODE_H_ +#define UPB_ENCODE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* If set, the results of serializing will be deterministic across all + * instances of this binary. There are no guarantees across different + * binary builds. + * + * If your proto contains maps, the encoder will need to malloc()/free() + * memory during encode. */ + kUpb_EncodeOption_Deterministic = 1, + + /* When set, unknown fields are not printed. */ + kUpb_EncodeOption_SkipUnknown = 2, + + /* When set, the encode will fail if any required fields are missing. */ + kUpb_EncodeOption_CheckRequired = 4, +}; + +#define UPB_ENCODE_MAXDEPTH(depth) ((depth) << 16) + +typedef enum { + kUpb_EncodeStatus_Ok = 0, + kUpb_EncodeStatus_OutOfMemory = 1, // Arena alloc failed + kUpb_EncodeStatus_MaxDepthExceeded = 2, // Exceeded UPB_ENCODE_MAXDEPTH + + // kUpb_EncodeOption_CheckRequired failed but the parse otherwise succeeded. + kUpb_EncodeStatus_MissingRequired = 3, +} upb_EncodeStatus; + +upb_EncodeStatus upb_Encode(const void* msg, const upb_MiniTable* l, + int options, upb_Arena* arena, char** buf, + size_t* size); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_ENCODE_H_ */ + #ifdef __cplusplus extern "C" { #endif -struct google_protobuf_FileDescriptorSet; -struct google_protobuf_FileDescriptorProto; -struct google_protobuf_DescriptorProto; -struct google_protobuf_DescriptorProto_ExtensionRange; -struct google_protobuf_DescriptorProto_ReservedRange; -struct google_protobuf_ExtensionRangeOptions; -struct google_protobuf_FieldDescriptorProto; -struct google_protobuf_OneofDescriptorProto; -struct google_protobuf_EnumDescriptorProto; -struct google_protobuf_EnumDescriptorProto_EnumReservedRange; -struct google_protobuf_EnumValueDescriptorProto; -struct google_protobuf_ServiceDescriptorProto; -struct google_protobuf_MethodDescriptorProto; -struct google_protobuf_FileOptions; -struct google_protobuf_MessageOptions; -struct google_protobuf_FieldOptions; -struct google_protobuf_OneofOptions; -struct google_protobuf_EnumOptions; -struct google_protobuf_EnumValueOptions; -struct google_protobuf_ServiceOptions; -struct google_protobuf_MethodOptions; -struct google_protobuf_UninterpretedOption; -struct google_protobuf_UninterpretedOption_NamePart; -struct google_protobuf_SourceCodeInfo; -struct google_protobuf_SourceCodeInfo_Location; -struct google_protobuf_GeneratedCodeInfo; -struct google_protobuf_GeneratedCodeInfo_Annotation; typedef struct google_protobuf_FileDescriptorSet google_protobuf_FileDescriptorSet; typedef struct google_protobuf_FileDescriptorProto google_protobuf_FileDescriptorProto; typedef struct google_protobuf_DescriptorProto google_protobuf_DescriptorProto; @@ -2343,33 +2466,33 @@ typedef struct google_protobuf_SourceCodeInfo google_protobuf_SourceCodeInfo; typedef struct google_protobuf_SourceCodeInfo_Location google_protobuf_SourceCodeInfo_Location; typedef struct google_protobuf_GeneratedCodeInfo google_protobuf_GeneratedCodeInfo; typedef struct google_protobuf_GeneratedCodeInfo_Annotation google_protobuf_GeneratedCodeInfo_Annotation; -extern const upb_MiniTable google_protobuf_FileDescriptorSet_msginit; -extern const upb_MiniTable google_protobuf_FileDescriptorProto_msginit; -extern const upb_MiniTable google_protobuf_DescriptorProto_msginit; -extern const upb_MiniTable google_protobuf_DescriptorProto_ExtensionRange_msginit; -extern const upb_MiniTable google_protobuf_DescriptorProto_ReservedRange_msginit; -extern const upb_MiniTable google_protobuf_ExtensionRangeOptions_msginit; -extern const upb_MiniTable google_protobuf_FieldDescriptorProto_msginit; -extern const upb_MiniTable google_protobuf_OneofDescriptorProto_msginit; -extern const upb_MiniTable google_protobuf_EnumDescriptorProto_msginit; -extern const upb_MiniTable google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit; -extern const upb_MiniTable google_protobuf_EnumValueDescriptorProto_msginit; -extern const upb_MiniTable google_protobuf_ServiceDescriptorProto_msginit; -extern const upb_MiniTable google_protobuf_MethodDescriptorProto_msginit; -extern const upb_MiniTable google_protobuf_FileOptions_msginit; -extern const upb_MiniTable google_protobuf_MessageOptions_msginit; -extern const upb_MiniTable google_protobuf_FieldOptions_msginit; -extern const upb_MiniTable google_protobuf_OneofOptions_msginit; -extern const upb_MiniTable google_protobuf_EnumOptions_msginit; -extern const upb_MiniTable google_protobuf_EnumValueOptions_msginit; -extern const upb_MiniTable google_protobuf_ServiceOptions_msginit; -extern const upb_MiniTable google_protobuf_MethodOptions_msginit; -extern const upb_MiniTable google_protobuf_UninterpretedOption_msginit; -extern const upb_MiniTable google_protobuf_UninterpretedOption_NamePart_msginit; -extern const upb_MiniTable google_protobuf_SourceCodeInfo_msginit; -extern const upb_MiniTable google_protobuf_SourceCodeInfo_Location_msginit; -extern const upb_MiniTable google_protobuf_GeneratedCodeInfo_msginit; -extern const upb_MiniTable google_protobuf_GeneratedCodeInfo_Annotation_msginit; +extern const upb_MiniTable google_protobuf_FileDescriptorSet_msg_init; +extern const upb_MiniTable google_protobuf_FileDescriptorProto_msg_init; +extern const upb_MiniTable google_protobuf_DescriptorProto_msg_init; +extern const upb_MiniTable google_protobuf_DescriptorProto_ExtensionRange_msg_init; +extern const upb_MiniTable google_protobuf_DescriptorProto_ReservedRange_msg_init; +extern const upb_MiniTable google_protobuf_ExtensionRangeOptions_msg_init; +extern const upb_MiniTable google_protobuf_FieldDescriptorProto_msg_init; +extern const upb_MiniTable google_protobuf_OneofDescriptorProto_msg_init; +extern const upb_MiniTable google_protobuf_EnumDescriptorProto_msg_init; +extern const upb_MiniTable google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init; +extern const upb_MiniTable google_protobuf_EnumValueDescriptorProto_msg_init; +extern const upb_MiniTable google_protobuf_ServiceDescriptorProto_msg_init; +extern const upb_MiniTable google_protobuf_MethodDescriptorProto_msg_init; +extern const upb_MiniTable google_protobuf_FileOptions_msg_init; +extern const upb_MiniTable google_protobuf_MessageOptions_msg_init; +extern const upb_MiniTable google_protobuf_FieldOptions_msg_init; +extern const upb_MiniTable google_protobuf_OneofOptions_msg_init; +extern const upb_MiniTable google_protobuf_EnumOptions_msg_init; +extern const upb_MiniTable google_protobuf_EnumValueOptions_msg_init; +extern const upb_MiniTable google_protobuf_ServiceOptions_msg_init; +extern const upb_MiniTable google_protobuf_MethodOptions_msg_init; +extern const upb_MiniTable google_protobuf_UninterpretedOption_msg_init; +extern const upb_MiniTable google_protobuf_UninterpretedOption_NamePart_msg_init; +extern const upb_MiniTable google_protobuf_SourceCodeInfo_msg_init; +extern const upb_MiniTable google_protobuf_SourceCodeInfo_Location_msg_init; +extern const upb_MiniTable google_protobuf_GeneratedCodeInfo_msg_init; +extern const upb_MiniTable google_protobuf_GeneratedCodeInfo_Annotation_msg_init; typedef enum { google_protobuf_FieldDescriptorProto_LABEL_OPTIONAL = 1, @@ -2416,6 +2539,12 @@ typedef enum { google_protobuf_FileOptions_LITE_RUNTIME = 3 } google_protobuf_FileOptions_OptimizeMode; +typedef enum { + google_protobuf_GeneratedCodeInfo_Annotation_NONE = 0, + google_protobuf_GeneratedCodeInfo_Annotation_SET = 1, + google_protobuf_GeneratedCodeInfo_Annotation_ALIAS = 2 +} google_protobuf_GeneratedCodeInfo_Annotation_Semantic; + typedef enum { google_protobuf_MethodOptions_IDEMPOTENCY_UNKNOWN = 0, google_protobuf_MethodOptions_NO_SIDE_EFFECTS = 1, @@ -2423,22 +2552,23 @@ typedef enum { } google_protobuf_MethodOptions_IdempotencyLevel; -extern const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enuminit; -extern const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enuminit; -extern const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enuminit; -extern const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enuminit; -extern const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enuminit; -extern const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enuminit; +extern const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enum_init; +extern const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enum_init; +extern const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enum_init; +extern const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enum_init; +extern const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enum_init; +extern const upb_MiniTable_Enum google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init; +extern const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enum_init; /* google.protobuf.FileDescriptorSet */ UPB_INLINE google_protobuf_FileDescriptorSet* google_protobuf_FileDescriptorSet_new(upb_Arena* arena) { - return (google_protobuf_FileDescriptorSet*)_upb_Message_New(&google_protobuf_FileDescriptorSet_msginit, arena); + return (google_protobuf_FileDescriptorSet*)_upb_Message_New(&google_protobuf_FileDescriptorSet_msg_init, arena); } UPB_INLINE google_protobuf_FileDescriptorSet* google_protobuf_FileDescriptorSet_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_FileDescriptorSet* ret = google_protobuf_FileDescriptorSet_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorSet_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorSet_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -2448,32 +2578,42 @@ UPB_INLINE google_protobuf_FileDescriptorSet* google_protobuf_FileDescriptorSet_ int options, upb_Arena* arena) { google_protobuf_FileDescriptorSet* ret = google_protobuf_FileDescriptorSet_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorSet_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorSet_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_FileDescriptorSet_serialize(const google_protobuf_FileDescriptorSet* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FileDescriptorSet_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FileDescriptorSet_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_FileDescriptorSet_serialize_ex(const google_protobuf_FileDescriptorSet* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FileDescriptorSet_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FileDescriptorSet_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_FileDescriptorSet_has_file(const google_protobuf_FileDescriptorSet* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE void google_protobuf_FileDescriptorSet_clear_file(const google_protobuf_FileDescriptorSet* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE const google_protobuf_FileDescriptorProto* const* google_protobuf_FileDescriptorSet_file(const google_protobuf_FileDescriptorSet* msg, size_t* len) { + return (const google_protobuf_FileDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE bool google_protobuf_FileDescriptorSet_has_file(const google_protobuf_FileDescriptorSet *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_FileDescriptorProto* const* google_protobuf_FileDescriptorSet_file(const google_protobuf_FileDescriptorSet *msg, size_t *len) { return (const google_protobuf_FileDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_mutable_file(google_protobuf_FileDescriptorSet *msg, size_t *len) { +UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_mutable_file(google_protobuf_FileDescriptorSet* msg, size_t* len) { return (google_protobuf_FileDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_resize_file(google_protobuf_FileDescriptorSet *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_resize_file(google_protobuf_FileDescriptorSet* msg, size_t len, upb_Arena* arena) { return (google_protobuf_FileDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorSet_add_file(google_protobuf_FileDescriptorSet *msg, upb_Arena *arena) { - struct google_protobuf_FileDescriptorProto* sub = (struct google_protobuf_FileDescriptorProto*)_upb_Message_New(&google_protobuf_FileDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorSet_add_file(google_protobuf_FileDescriptorSet* msg, upb_Arena* arena) { + struct google_protobuf_FileDescriptorProto* sub = (struct google_protobuf_FileDescriptorProto*)_upb_Message_New(&google_protobuf_FileDescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -2481,12 +2621,12 @@ UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_FileDescr /* google.protobuf.FileDescriptorProto */ UPB_INLINE google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorProto_new(upb_Arena* arena) { - return (google_protobuf_FileDescriptorProto*)_upb_Message_New(&google_protobuf_FileDescriptorProto_msginit, arena); + return (google_protobuf_FileDescriptorProto*)_upb_Message_New(&google_protobuf_FileDescriptorProto_msg_init, arena); } UPB_INLINE google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_FileDescriptorProto* ret = google_protobuf_FileDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorProto_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -2496,49 +2636,136 @@ UPB_INLINE google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorPr int options, upb_Arena* arena) { google_protobuf_FileDescriptorProto* ret = google_protobuf_FileDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorProto_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorProto_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_FileDescriptorProto_serialize(const google_protobuf_FileDescriptorProto* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FileDescriptorProto_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FileDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_FileDescriptorProto_serialize_ex(const google_protobuf_FileDescriptorProto* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FileDescriptorProto_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FileDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_name(const google_protobuf_FileDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_name(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_name(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_name(const google_protobuf_FileDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_package(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_package(const google_protobuf_FileDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_package(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_package(const google_protobuf_FileDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); } -UPB_INLINE upb_StringView const* google_protobuf_FileDescriptorProto_dependency(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_message_type(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); } -UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_FileDescriptorProto_message_type(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_enum_type(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(44, 88)); } -UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_FileDescriptorProto_enum_type(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_service(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(48, 96)); } -UPB_INLINE const google_protobuf_ServiceDescriptorProto* const* google_protobuf_FileDescriptorProto_service(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_ServiceDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(48, 96), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_extension(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(52, 104)); } -UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_FileDescriptorProto_extension(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(52, 104), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_options(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_dependency(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(20, 40)); +} +UPB_INLINE upb_StringView const* google_protobuf_FileDescriptorProto_dependency(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_message_type(const google_protobuf_FileDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_message_type(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(24, 48)); +} +UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_FileDescriptorProto_message_type(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_enum_type(const google_protobuf_FileDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 56)); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_enum_type(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(28, 56)); +} +UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_FileDescriptorProto_enum_type(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_service(const google_protobuf_FileDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(32, 64)); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_service(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(32, 64)); +} +UPB_INLINE const google_protobuf_ServiceDescriptorProto* const* google_protobuf_FileDescriptorProto_service(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (const google_protobuf_ServiceDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(32, 64), len); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_extension(const google_protobuf_FileDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(36, 72)); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_extension(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(36, 72)); +} +UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_FileDescriptorProto_extension(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_options(const google_protobuf_FileDescriptorProto* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_options(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(40, 80), const upb_Message*) = NULL; + _upb_clearhas(msg, 3); +} UPB_INLINE const google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_options(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const google_protobuf_FileOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(40, 80), const google_protobuf_FileOptions*); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_source_code_info(const google_protobuf_FileDescriptorProto* msg) { + return _upb_hasbit(msg, 4); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_source_code_info(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(44, 88), const upb_Message*) = NULL; + _upb_clearhas(msg, 4); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_source_code_info(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 4); } UPB_INLINE const google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_source_code_info(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(32, 64), const google_protobuf_SourceCodeInfo*); + return *UPB_PTR_AT(msg, UPB_SIZE(44, 88), const google_protobuf_SourceCodeInfo*); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_public_dependency(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(48, 96)); +} +UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_public_dependency(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(48, 96), len); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_weak_dependency(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(52, 104)); +} +UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_weak_dependency(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(52, 104), len); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_syntax(const google_protobuf_FileDescriptorProto* msg) { + return _upb_hasbit(msg, 5); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_syntax(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(56, 112), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 5); } -UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_public_dependency(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(56, 112), len); } -UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_weak_dependency(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(60, 120), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_syntax(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 5); } UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_syntax(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(56, 112), upb_StringView); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_edition(const google_protobuf_FileDescriptorProto* msg) { + return _upb_hasbit(msg, 6); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_edition(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(64, 128), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 6); +} +UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_edition(const google_protobuf_FileDescriptorProto* msg) { + return *UPB_PTR_AT(msg, UPB_SIZE(64, 128), upb_StringView); } UPB_INLINE void google_protobuf_FileDescriptorProto_set_name(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { @@ -2549,76 +2776,71 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_set_package(google_protobuf_ _upb_sethas(msg, 2); *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = value; } -UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_mutable_dependency(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len); +UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_mutable_dependency(google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_resize_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { - return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(3, 4), arena); +UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_resize_dependency(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { + return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(3, 4), arena); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_add_dependency(google_protobuf_FileDescriptorProto *msg, upb_StringView val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(36, 72), UPB_SIZE(3, 4), &val, - arena); +UPB_INLINE bool google_protobuf_FileDescriptorProto_add_dependency(google_protobuf_FileDescriptorProto* msg, upb_StringView val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), UPB_SIZE(3, 4), &val, arena); } -UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_mutable_message_type(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(40, 80), len); +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_mutable_message_type(google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); } -UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_resize_message_type(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(40, 80), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_resize_message_type(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_FileDescriptorProto_add_message_type(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) { - struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(40, 80), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_FileDescriptorProto_add_message_type(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_mutable_enum_type(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(44, 88), len); +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_mutable_enum_type(google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); } -UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_resize_enum_type(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(44, 88), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_resize_enum_type(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_FileDescriptorProto_add_enum_type(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) { - struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(44, 88), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_FileDescriptorProto_add_enum_type(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_mutable_service(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (google_protobuf_ServiceDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(48, 96), len); +UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_mutable_service(google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (google_protobuf_ServiceDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 64), len); } -UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_resize_service(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_ServiceDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(48, 96), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_resize_service(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_ServiceDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(32, 64), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_ServiceDescriptorProto* google_protobuf_FileDescriptorProto_add_service(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) { - struct google_protobuf_ServiceDescriptorProto* sub = (struct google_protobuf_ServiceDescriptorProto*)_upb_Message_New(&google_protobuf_ServiceDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(48, 96), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_ServiceDescriptorProto* google_protobuf_FileDescriptorProto_add_service(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_ServiceDescriptorProto* sub = (struct google_protobuf_ServiceDescriptorProto*)_upb_Message_New(&google_protobuf_ServiceDescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(32, 64), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_mutable_extension(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(52, 104), len); +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_mutable_extension(google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len); } -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_resize_extension(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(52, 104), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_resize_extension(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_FileDescriptorProto_add_extension(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) { - struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(52, 104), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_FileDescriptorProto_add_extension(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(36, 72), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_FileDescriptorProto_set_options(google_protobuf_FileDescriptorProto *msg, google_protobuf_FileOptions* value) { _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(28, 56), google_protobuf_FileOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(40, 80), google_protobuf_FileOptions*) = value; } -UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_mutable_options(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_mutable_options(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_FileOptions* sub = (struct google_protobuf_FileOptions*)google_protobuf_FileDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_FileOptions*)_upb_Message_New(&google_protobuf_FileOptions_msginit, arena); + sub = (struct google_protobuf_FileOptions*)_upb_Message_New(&google_protobuf_FileOptions_msg_init, arena); if (!sub) return NULL; google_protobuf_FileDescriptorProto_set_options(msg, sub); } @@ -2626,51 +2848,53 @@ UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorPro } UPB_INLINE void google_protobuf_FileDescriptorProto_set_source_code_info(google_protobuf_FileDescriptorProto *msg, google_protobuf_SourceCodeInfo* value) { _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(32, 64), google_protobuf_SourceCodeInfo*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(44, 88), google_protobuf_SourceCodeInfo*) = value; } -UPB_INLINE struct google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_mutable_source_code_info(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_mutable_source_code_info(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_SourceCodeInfo* sub = (struct google_protobuf_SourceCodeInfo*)google_protobuf_FileDescriptorProto_source_code_info(msg); if (sub == NULL) { - sub = (struct google_protobuf_SourceCodeInfo*)_upb_Message_New(&google_protobuf_SourceCodeInfo_msginit, arena); + sub = (struct google_protobuf_SourceCodeInfo*)_upb_Message_New(&google_protobuf_SourceCodeInfo_msg_init, arena); if (!sub) return NULL; google_protobuf_FileDescriptorProto_set_source_code_info(msg, sub); } return sub; } -UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_public_dependency(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(56, 112), len); +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_public_dependency(google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(48, 96), len); } -UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_public_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(56, 112), len, 2, arena); +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_public_dependency(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(48, 96), len, 2, arena); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_add_public_dependency(google_protobuf_FileDescriptorProto *msg, int32_t val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(56, 112), 2, &val, - arena); +UPB_INLINE bool google_protobuf_FileDescriptorProto_add_public_dependency(google_protobuf_FileDescriptorProto* msg, int32_t val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(48, 96), 2, &val, arena); } -UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_weak_dependency(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(60, 120), len); +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_weak_dependency(google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(52, 104), len); } -UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_weak_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(60, 120), len, 2, arena); +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_weak_dependency(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(52, 104), len, 2, arena); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_add_weak_dependency(google_protobuf_FileDescriptorProto *msg, int32_t val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(60, 120), 2, &val, - arena); +UPB_INLINE bool google_protobuf_FileDescriptorProto_add_weak_dependency(google_protobuf_FileDescriptorProto* msg, int32_t val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(52, 104), 2, &val, arena); } UPB_INLINE void google_protobuf_FileDescriptorProto_set_syntax(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(56, 112), upb_StringView) = value; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_edition(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { + _upb_sethas(msg, 6); + *UPB_PTR_AT(msg, UPB_SIZE(64, 128), upb_StringView) = value; } /* google.protobuf.DescriptorProto */ UPB_INLINE google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_new(upb_Arena* arena) { - return (google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msginit, arena); + return (google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msg_init, arena); } UPB_INLINE google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_DescriptorProto* ret = google_protobuf_DescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -2680,171 +2904,233 @@ UPB_INLINE google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_pars int options, upb_Arena* arena) { google_protobuf_DescriptorProto* ret = google_protobuf_DescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_DescriptorProto_serialize(const google_protobuf_DescriptorProto* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_DescriptorProto_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_DescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_DescriptorProto_serialize_ex(const google_protobuf_DescriptorProto* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_DescriptorProto_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_DescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_name(const google_protobuf_DescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_name(const google_protobuf_DescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_name(const google_protobuf_DescriptorProto *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE upb_StringView google_protobuf_DescriptorProto_name(const google_protobuf_DescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_field(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); } -UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_field(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_nested_type(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); } -UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_DescriptorProto_nested_type(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_enum_type(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); } -UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_DescriptorProto_enum_type(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_extension_range(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 56)); } -UPB_INLINE const google_protobuf_DescriptorProto_ExtensionRange* const* google_protobuf_DescriptorProto_extension_range(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_DescriptorProto_ExtensionRange* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_extension(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(32, 64)); } -UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_extension(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(32, 64), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_options(const google_protobuf_DescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_DescriptorProto_has_field(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 24)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_field(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(12, 24)); +} +UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_field(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(12, 24), len); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_nested_type(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_nested_type(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(16, 32)); +} +UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_DescriptorProto_nested_type(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_enum_type(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_enum_type(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(20, 40)); +} +UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_DescriptorProto_enum_type(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_extension_range(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_extension_range(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(24, 48)); +} +UPB_INLINE const google_protobuf_DescriptorProto_ExtensionRange* const* google_protobuf_DescriptorProto_extension_range(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_DescriptorProto_ExtensionRange* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_extension(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 56)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_extension(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(28, 56)); +} +UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_extension(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_options(const google_protobuf_DescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_options(const google_protobuf_DescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(32, 64), const upb_Message*) = NULL; + _upb_clearhas(msg, 2); +} UPB_INLINE const google_protobuf_MessageOptions* google_protobuf_DescriptorProto_options(const google_protobuf_DescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_MessageOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(32, 64), const google_protobuf_MessageOptions*); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_oneof_decl(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(36, 72)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_oneof_decl(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(36, 72)); +} +UPB_INLINE const google_protobuf_OneofDescriptorProto* const* google_protobuf_DescriptorProto_oneof_decl(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_OneofDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_reserved_range(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_reserved_range(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(40, 80)); +} +UPB_INLINE const google_protobuf_DescriptorProto_ReservedRange* const* google_protobuf_DescriptorProto_reserved_range(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_DescriptorProto_ReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_reserved_name(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(44, 88)); +} +UPB_INLINE upb_StringView const* google_protobuf_DescriptorProto_reserved_name(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_oneof_decl(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(36, 72)); } -UPB_INLINE const google_protobuf_OneofDescriptorProto* const* google_protobuf_DescriptorProto_oneof_decl(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_OneofDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_reserved_range(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); } -UPB_INLINE const google_protobuf_DescriptorProto_ReservedRange* const* google_protobuf_DescriptorProto_reserved_range(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_DescriptorProto_ReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); } -UPB_INLINE upb_StringView const* google_protobuf_DescriptorProto_reserved_name(const google_protobuf_DescriptorProto *msg, size_t *len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); } UPB_INLINE void google_protobuf_DescriptorProto_set_name(google_protobuf_DescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 1); *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; } -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_field(google_protobuf_DescriptorProto *msg, size_t *len) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_field(google_protobuf_DescriptorProto* msg, size_t* len) { + return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 24), len); } -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_field(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_field(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 24), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_field(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { - struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_field(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(12, 24), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_mutable_nested_type(google_protobuf_DescriptorProto *msg, size_t *len) { - return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_mutable_nested_type(google_protobuf_DescriptorProto* msg, size_t* len) { + return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); } -UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_resize_nested_type(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_resize_nested_type(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_add_nested_type(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { - struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_add_nested_type(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_mutable_enum_type(google_protobuf_DescriptorProto *msg, size_t *len) { - return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_mutable_enum_type(google_protobuf_DescriptorProto* msg, size_t* len) { + return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_resize_enum_type(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_resize_enum_type(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_DescriptorProto_add_enum_type(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { - struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_DescriptorProto_add_enum_type(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_mutable_extension_range(google_protobuf_DescriptorProto *msg, size_t *len) { - return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); +UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_mutable_extension_range(google_protobuf_DescriptorProto* msg, size_t* len) { + return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); } -UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_resize_extension_range(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_resize_extension_range(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_add_extension_range(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { - struct google_protobuf_DescriptorProto_ExtensionRange* sub = (struct google_protobuf_DescriptorProto_ExtensionRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ExtensionRange_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_add_extension_range(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_DescriptorProto_ExtensionRange* sub = (struct google_protobuf_DescriptorProto_ExtensionRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ExtensionRange_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_extension(google_protobuf_DescriptorProto *msg, size_t *len) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 64), len); +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_extension(google_protobuf_DescriptorProto* msg, size_t* len) { + return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); } -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_extension(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(32, 64), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_extension(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_extension(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { - struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(32, 64), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_extension(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_DescriptorProto_set_options(google_protobuf_DescriptorProto *msg, google_protobuf_MessageOptions* value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_MessageOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(32, 64), google_protobuf_MessageOptions*) = value; } -UPB_INLINE struct google_protobuf_MessageOptions* google_protobuf_DescriptorProto_mutable_options(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_MessageOptions* google_protobuf_DescriptorProto_mutable_options(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_MessageOptions* sub = (struct google_protobuf_MessageOptions*)google_protobuf_DescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_MessageOptions*)_upb_Message_New(&google_protobuf_MessageOptions_msginit, arena); + sub = (struct google_protobuf_MessageOptions*)_upb_Message_New(&google_protobuf_MessageOptions_msg_init, arena); if (!sub) return NULL; google_protobuf_DescriptorProto_set_options(msg, sub); } return sub; } -UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_mutable_oneof_decl(google_protobuf_DescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_mutable_oneof_decl(google_protobuf_DescriptorProto* msg, size_t* len) { return (google_protobuf_OneofDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len); } -UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_resize_oneof_decl(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_resize_oneof_decl(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_OneofDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_OneofDescriptorProto* google_protobuf_DescriptorProto_add_oneof_decl(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { - struct google_protobuf_OneofDescriptorProto* sub = (struct google_protobuf_OneofDescriptorProto*)_upb_Message_New(&google_protobuf_OneofDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(36, 72), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_OneofDescriptorProto* google_protobuf_DescriptorProto_add_oneof_decl(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_OneofDescriptorProto* sub = (struct google_protobuf_OneofDescriptorProto*)_upb_Message_New(&google_protobuf_OneofDescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(36, 72), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_mutable_reserved_range(google_protobuf_DescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_mutable_reserved_range(google_protobuf_DescriptorProto* msg, size_t* len) { return (google_protobuf_DescriptorProto_ReservedRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(40, 80), len); } -UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_resize_reserved_range(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_resize_reserved_range(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_DescriptorProto_ReservedRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(40, 80), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_add_reserved_range(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { - struct google_protobuf_DescriptorProto_ReservedRange* sub = (struct google_protobuf_DescriptorProto_ReservedRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ReservedRange_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(40, 80), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_add_reserved_range(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_DescriptorProto_ReservedRange* sub = (struct google_protobuf_DescriptorProto_ReservedRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ReservedRange_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(40, 80), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE upb_StringView* google_protobuf_DescriptorProto_mutable_reserved_name(google_protobuf_DescriptorProto *msg, size_t *len) { +UPB_INLINE upb_StringView* google_protobuf_DescriptorProto_mutable_reserved_name(google_protobuf_DescriptorProto* msg, size_t* len) { return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(44, 88), len); } -UPB_INLINE upb_StringView* google_protobuf_DescriptorProto_resize_reserved_name(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE upb_StringView* google_protobuf_DescriptorProto_resize_reserved_name(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(44, 88), len, UPB_SIZE(3, 4), arena); } -UPB_INLINE bool google_protobuf_DescriptorProto_add_reserved_name(google_protobuf_DescriptorProto *msg, upb_StringView val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(44, 88), UPB_SIZE(3, 4), &val, - arena); +UPB_INLINE bool google_protobuf_DescriptorProto_add_reserved_name(google_protobuf_DescriptorProto* msg, upb_StringView val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(44, 88), UPB_SIZE(3, 4), &val, arena); } /* google.protobuf.DescriptorProto.ExtensionRange */ UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_ExtensionRange_new(upb_Arena* arena) { - return (google_protobuf_DescriptorProto_ExtensionRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ExtensionRange_msginit, arena); + return (google_protobuf_DescriptorProto_ExtensionRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ExtensionRange_msg_init, arena); } UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_ExtensionRange_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_DescriptorProto_ExtensionRange* ret = google_protobuf_DescriptorProto_ExtensionRange_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ExtensionRange_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ExtensionRange_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -2854,28 +3140,50 @@ UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_Descr int options, upb_Arena* arena) { google_protobuf_DescriptorProto_ExtensionRange* ret = google_protobuf_DescriptorProto_ExtensionRange_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ExtensionRange_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ExtensionRange_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_DescriptorProto_ExtensionRange_serialize(const google_protobuf_DescriptorProto_ExtensionRange* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_DescriptorProto_ExtensionRange_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_DescriptorProto_ExtensionRange_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_DescriptorProto_ExtensionRange_serialize_ex(const google_protobuf_DescriptorProto_ExtensionRange* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_DescriptorProto_ExtensionRange_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_DescriptorProto_ExtensionRange_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_start(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_start(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_start(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_start(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_end(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_end(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_end(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_end(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } -UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_options(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 16), const upb_Message*) = NULL; + _upb_clearhas(msg, 3); +} UPB_INLINE const google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 16), const google_protobuf_ExtensionRangeOptions*); } @@ -2892,10 +3200,10 @@ UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_options(googl _upb_sethas(msg, 3); *UPB_PTR_AT(msg, UPB_SIZE(12, 16), google_protobuf_ExtensionRangeOptions*) = value; } -UPB_INLINE struct google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_mutable_options(google_protobuf_DescriptorProto_ExtensionRange *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_mutable_options(google_protobuf_DescriptorProto_ExtensionRange* msg, upb_Arena* arena) { struct google_protobuf_ExtensionRangeOptions* sub = (struct google_protobuf_ExtensionRangeOptions*)google_protobuf_DescriptorProto_ExtensionRange_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_ExtensionRangeOptions*)_upb_Message_New(&google_protobuf_ExtensionRangeOptions_msginit, arena); + sub = (struct google_protobuf_ExtensionRangeOptions*)_upb_Message_New(&google_protobuf_ExtensionRangeOptions_msg_init, arena); if (!sub) return NULL; google_protobuf_DescriptorProto_ExtensionRange_set_options(msg, sub); } @@ -2905,12 +3213,12 @@ UPB_INLINE struct google_protobuf_ExtensionRangeOptions* google_protobuf_Descrip /* google.protobuf.DescriptorProto.ReservedRange */ UPB_INLINE google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_ReservedRange_new(upb_Arena* arena) { - return (google_protobuf_DescriptorProto_ReservedRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ReservedRange_msginit, arena); + return (google_protobuf_DescriptorProto_ReservedRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ReservedRange_msg_init, arena); } UPB_INLINE google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_ReservedRange_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_DescriptorProto_ReservedRange* ret = google_protobuf_DescriptorProto_ReservedRange_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ReservedRange_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ReservedRange_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -2920,24 +3228,40 @@ UPB_INLINE google_protobuf_DescriptorProto_ReservedRange* google_protobuf_Descri int options, upb_Arena* arena) { google_protobuf_DescriptorProto_ReservedRange* ret = google_protobuf_DescriptorProto_ReservedRange_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ReservedRange_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ReservedRange_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_DescriptorProto_ReservedRange_serialize(const google_protobuf_DescriptorProto_ReservedRange* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_DescriptorProto_ReservedRange_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_DescriptorProto_ReservedRange_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_DescriptorProto_ReservedRange_serialize_ex(const google_protobuf_DescriptorProto_ReservedRange* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_DescriptorProto_ReservedRange_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_DescriptorProto_ReservedRange_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_start(const google_protobuf_DescriptorProto_ReservedRange* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_clear_start(const google_protobuf_DescriptorProto_ReservedRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_start(const google_protobuf_DescriptorProto_ReservedRange *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_start(const google_protobuf_DescriptorProto_ReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_end(const google_protobuf_DescriptorProto_ReservedRange *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_end(const google_protobuf_DescriptorProto_ReservedRange* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_clear_end(const google_protobuf_DescriptorProto_ReservedRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_end(const google_protobuf_DescriptorProto_ReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } @@ -2954,12 +3278,12 @@ UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_end(google_pro /* google.protobuf.ExtensionRangeOptions */ UPB_INLINE google_protobuf_ExtensionRangeOptions* google_protobuf_ExtensionRangeOptions_new(upb_Arena* arena) { - return (google_protobuf_ExtensionRangeOptions*)_upb_Message_New(&google_protobuf_ExtensionRangeOptions_msginit, arena); + return (google_protobuf_ExtensionRangeOptions*)_upb_Message_New(&google_protobuf_ExtensionRangeOptions_msg_init, arena); } UPB_INLINE google_protobuf_ExtensionRangeOptions* google_protobuf_ExtensionRangeOptions_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_ExtensionRangeOptions* ret = google_protobuf_ExtensionRangeOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_ExtensionRangeOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_ExtensionRangeOptions_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -2969,32 +3293,42 @@ UPB_INLINE google_protobuf_ExtensionRangeOptions* google_protobuf_ExtensionRange int options, upb_Arena* arena) { google_protobuf_ExtensionRangeOptions* ret = google_protobuf_ExtensionRangeOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_ExtensionRangeOptions_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_ExtensionRangeOptions_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_ExtensionRangeOptions_serialize(const google_protobuf_ExtensionRangeOptions* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_ExtensionRangeOptions_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_ExtensionRangeOptions_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_ExtensionRangeOptions_serialize_ex(const google_protobuf_ExtensionRangeOptions* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_ExtensionRangeOptions_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_ExtensionRangeOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_has_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_clear_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ExtensionRangeOptions_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE bool google_protobuf_ExtensionRangeOptions_has_uninterpreted_option(const google_protobuf_ExtensionRangeOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ExtensionRangeOptions_uninterpreted_option(const google_protobuf_ExtensionRangeOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_mutable_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_mutable_uninterpreted_option(google_protobuf_ExtensionRangeOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_resize_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_resize_uninterpreted_option(google_protobuf_ExtensionRangeOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ExtensionRangeOptions_add_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, upb_Arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ExtensionRangeOptions_add_uninterpreted_option(google_protobuf_ExtensionRangeOptions* msg, upb_Arena* arena) { + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -3002,12 +3336,12 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_Extension /* google.protobuf.FieldDescriptorProto */ UPB_INLINE google_protobuf_FieldDescriptorProto* google_protobuf_FieldDescriptorProto_new(upb_Arena* arena) { - return (google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena); + return (google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msg_init, arena); } UPB_INLINE google_protobuf_FieldDescriptorProto* google_protobuf_FieldDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_FieldDescriptorProto* ret = google_protobuf_FieldDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FieldDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_FieldDescriptorProto_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3017,60 +3351,130 @@ UPB_INLINE google_protobuf_FieldDescriptorProto* google_protobuf_FieldDescriptor int options, upb_Arena* arena) { google_protobuf_FieldDescriptorProto* ret = google_protobuf_FieldDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FieldDescriptorProto_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_FieldDescriptorProto_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_FieldDescriptorProto_serialize(const google_protobuf_FieldDescriptorProto* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FieldDescriptorProto_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FieldDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_FieldDescriptorProto_serialize_ex(const google_protobuf_FieldDescriptorProto* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FieldDescriptorProto_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FieldDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_name(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_name(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(24, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_name(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), upb_StringView); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_extendee(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_extendee(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_extendee(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(32, 40), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_extendee(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 40), upb_StringView); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_number(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_number(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_number(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 3); +} UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_number(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t); + return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_label(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 4); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_label(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 4); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_label(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 4); } UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_label(const google_protobuf_FieldDescriptorProto* msg) { - return google_protobuf_FieldDescriptorProto_has_label(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) : 1; + return google_protobuf_FieldDescriptorProto_has_label(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) : 1; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 5); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_type(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = 0; + _upb_clearhas(msg, 5); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 5); } UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_type(const google_protobuf_FieldDescriptorProto* msg) { - return google_protobuf_FieldDescriptorProto_has_type(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) : 1; + return google_protobuf_FieldDescriptorProto_has_type(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) : 1; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type_name(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 6); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_type_name(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(40, 56), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 6); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 6); } UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_type_name(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(40, 56), upb_StringView); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_default_value(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 7); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_default_value(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 7); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_default_value(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(48, 72), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 7); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_default_value(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(48, 72), upb_StringView); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_options(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 8); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_options(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 8); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_options(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(56, 88), const upb_Message*) = NULL; + _upb_clearhas(msg, 8); +} UPB_INLINE const google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_options(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(64, 104), const google_protobuf_FieldOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(56, 88), const google_protobuf_FieldOptions*); +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 9); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t) = 0; + _upb_clearhas(msg, 9); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_oneof_index(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 9); } UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_json_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 10); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_json_name(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 10); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_json_name(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(60, 96), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 10); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_json_name(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(56, 88), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(60, 96), upb_StringView); +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 11); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(20, 20), bool) = 0; + _upb_clearhas(msg, 11); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_proto3_optional(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 11); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 20), bool); } @@ -3085,15 +3489,15 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_set_extendee(google_protobu } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_number(google_protobuf_FieldDescriptorProto *msg, int32_t value) { _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_label(google_protobuf_FieldDescriptorProto *msg, int32_t value) { _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type(google_protobuf_FieldDescriptorProto *msg, int32_t value) { _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = value; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 6); @@ -3105,12 +3509,12 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_set_default_value(google_pr } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_options(google_protobuf_FieldDescriptorProto *msg, google_protobuf_FieldOptions* value) { _upb_sethas(msg, 8); - *UPB_PTR_AT(msg, UPB_SIZE(64, 104), google_protobuf_FieldOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(56, 88), google_protobuf_FieldOptions*) = value; } -UPB_INLINE struct google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_mutable_options(google_protobuf_FieldDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_mutable_options(google_protobuf_FieldDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_FieldOptions* sub = (struct google_protobuf_FieldOptions*)google_protobuf_FieldDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_FieldOptions*)_upb_Message_New(&google_protobuf_FieldOptions_msginit, arena); + sub = (struct google_protobuf_FieldOptions*)_upb_Message_New(&google_protobuf_FieldOptions_msg_init, arena); if (!sub) return NULL; google_protobuf_FieldDescriptorProto_set_options(msg, sub); } @@ -3122,7 +3526,7 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_set_oneof_index(google_prot } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_json_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 10); - *UPB_PTR_AT(msg, UPB_SIZE(56, 88), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(60, 96), upb_StringView) = value; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_proto3_optional(google_protobuf_FieldDescriptorProto *msg, bool value) { _upb_sethas(msg, 11); @@ -3132,12 +3536,12 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_set_proto3_optional(google_ /* google.protobuf.OneofDescriptorProto */ UPB_INLINE google_protobuf_OneofDescriptorProto* google_protobuf_OneofDescriptorProto_new(upb_Arena* arena) { - return (google_protobuf_OneofDescriptorProto*)_upb_Message_New(&google_protobuf_OneofDescriptorProto_msginit, arena); + return (google_protobuf_OneofDescriptorProto*)_upb_Message_New(&google_protobuf_OneofDescriptorProto_msg_init, arena); } UPB_INLINE google_protobuf_OneofDescriptorProto* google_protobuf_OneofDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_OneofDescriptorProto* ret = google_protobuf_OneofDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_OneofDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_OneofDescriptorProto_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3147,24 +3551,40 @@ UPB_INLINE google_protobuf_OneofDescriptorProto* google_protobuf_OneofDescriptor int options, upb_Arena* arena) { google_protobuf_OneofDescriptorProto* ret = google_protobuf_OneofDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_OneofDescriptorProto_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_OneofDescriptorProto_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_OneofDescriptorProto_serialize(const google_protobuf_OneofDescriptorProto* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_OneofDescriptorProto_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_OneofDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_OneofDescriptorProto_serialize_ex(const google_protobuf_OneofDescriptorProto* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_OneofDescriptorProto_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_OneofDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_name(const google_protobuf_OneofDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_OneofDescriptorProto_clear_name(const google_protobuf_OneofDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_name(const google_protobuf_OneofDescriptorProto *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE upb_StringView google_protobuf_OneofDescriptorProto_name(const google_protobuf_OneofDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_options(const google_protobuf_OneofDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_options(const google_protobuf_OneofDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_OneofDescriptorProto_clear_options(const google_protobuf_OneofDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const upb_Message*) = NULL; + _upb_clearhas(msg, 2); +} UPB_INLINE const google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_options(const google_protobuf_OneofDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_OneofOptions*); } @@ -3177,10 +3597,10 @@ UPB_INLINE void google_protobuf_OneofDescriptorProto_set_options(google_protobuf _upb_sethas(msg, 2); *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_OneofOptions*) = value; } -UPB_INLINE struct google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_mutable_options(google_protobuf_OneofDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_mutable_options(google_protobuf_OneofDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_OneofOptions* sub = (struct google_protobuf_OneofOptions*)google_protobuf_OneofDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_OneofOptions*)_upb_Message_New(&google_protobuf_OneofOptions_msginit, arena); + sub = (struct google_protobuf_OneofOptions*)_upb_Message_New(&google_protobuf_OneofOptions_msg_init, arena); if (!sub) return NULL; google_protobuf_OneofDescriptorProto_set_options(msg, sub); } @@ -3190,12 +3610,12 @@ UPB_INLINE struct google_protobuf_OneofOptions* google_protobuf_OneofDescriptorP /* google.protobuf.EnumDescriptorProto */ UPB_INLINE google_protobuf_EnumDescriptorProto* google_protobuf_EnumDescriptorProto_new(upb_Arena* arena) { - return (google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msginit, arena); + return (google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msg_init, arena); } UPB_INLINE google_protobuf_EnumDescriptorProto* google_protobuf_EnumDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_EnumDescriptorProto* ret = google_protobuf_EnumDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3205,96 +3625,128 @@ UPB_INLINE google_protobuf_EnumDescriptorProto* google_protobuf_EnumDescriptorPr int options, upb_Arena* arena) { google_protobuf_EnumDescriptorProto* ret = google_protobuf_EnumDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_EnumDescriptorProto_serialize(const google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumDescriptorProto_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_EnumDescriptorProto_serialize_ex(const google_protobuf_EnumDescriptorProto* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumDescriptorProto_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_name(const google_protobuf_EnumDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_name(const google_protobuf_EnumDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_name(const google_protobuf_EnumDescriptorProto *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE upb_StringView google_protobuf_EnumDescriptorProto_name(const google_protobuf_EnumDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_value(const google_protobuf_EnumDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); } -UPB_INLINE const google_protobuf_EnumValueDescriptorProto* const* google_protobuf_EnumDescriptorProto_value(const google_protobuf_EnumDescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumValueDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_options(const google_protobuf_EnumDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_value(const google_protobuf_EnumDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 24)); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_value(const google_protobuf_EnumDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(12, 24)); +} +UPB_INLINE const google_protobuf_EnumValueDescriptorProto* const* google_protobuf_EnumDescriptorProto_value(const google_protobuf_EnumDescriptorProto* msg, size_t* len) { + return (const google_protobuf_EnumValueDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(12, 24), len); +} +UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_options(const google_protobuf_EnumDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_options(const google_protobuf_EnumDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const upb_Message*) = NULL; + _upb_clearhas(msg, 2); +} UPB_INLINE const google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_options(const google_protobuf_EnumDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_EnumOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const google_protobuf_EnumOptions*); +} +UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_reserved_range(const google_protobuf_EnumDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_reserved_range(const google_protobuf_EnumDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(20, 40)); +} +UPB_INLINE const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* google_protobuf_EnumDescriptorProto_reserved_range(const google_protobuf_EnumDescriptorProto* msg, size_t* len) { + return (const google_protobuf_EnumDescriptorProto_EnumReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_reserved_name(const google_protobuf_EnumDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(24, 48)); +} +UPB_INLINE upb_StringView const* google_protobuf_EnumDescriptorProto_reserved_name(const google_protobuf_EnumDescriptorProto* msg, size_t* len) { + return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_reserved_range(const google_protobuf_EnumDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); } -UPB_INLINE const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* google_protobuf_EnumDescriptorProto_reserved_range(const google_protobuf_EnumDescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumDescriptorProto_EnumReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE upb_StringView const* google_protobuf_EnumDescriptorProto_reserved_name(const google_protobuf_EnumDescriptorProto *msg, size_t *len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } UPB_INLINE void google_protobuf_EnumDescriptorProto_set_name(google_protobuf_EnumDescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 1); *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; } -UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_mutable_value(google_protobuf_EnumDescriptorProto *msg, size_t *len) { - return (google_protobuf_EnumValueDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); +UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_mutable_value(google_protobuf_EnumDescriptorProto* msg, size_t* len) { + return (google_protobuf_EnumValueDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 24), len); } -UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_resize_value(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_EnumValueDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_resize_value(google_protobuf_EnumDescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_EnumValueDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 24), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumDescriptorProto_add_value(google_protobuf_EnumDescriptorProto *msg, upb_Arena *arena) { - struct google_protobuf_EnumValueDescriptorProto* sub = (struct google_protobuf_EnumValueDescriptorProto*)_upb_Message_New(&google_protobuf_EnumValueDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumDescriptorProto_add_value(google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_EnumValueDescriptorProto* sub = (struct google_protobuf_EnumValueDescriptorProto*)_upb_Message_New(&google_protobuf_EnumValueDescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(12, 24), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_EnumDescriptorProto_set_options(google_protobuf_EnumDescriptorProto *msg, google_protobuf_EnumOptions* value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_EnumOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), google_protobuf_EnumOptions*) = value; } -UPB_INLINE struct google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_mutable_options(google_protobuf_EnumDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_mutable_options(google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumOptions* sub = (struct google_protobuf_EnumOptions*)google_protobuf_EnumDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_EnumOptions*)_upb_Message_New(&google_protobuf_EnumOptions_msginit, arena); + sub = (struct google_protobuf_EnumOptions*)_upb_Message_New(&google_protobuf_EnumOptions_msg_init, arena); if (!sub) return NULL; google_protobuf_EnumDescriptorProto_set_options(msg, sub); } return sub; } -UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_mutable_reserved_range(google_protobuf_EnumDescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_mutable_reserved_range(google_protobuf_EnumDescriptorProto* msg, size_t* len) { return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_resize_reserved_range(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_resize_reserved_range(google_protobuf_EnumDescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_add_reserved_range(google_protobuf_EnumDescriptorProto *msg, upb_Arena *arena) { - struct google_protobuf_EnumDescriptorProto_EnumReservedRange* sub = (struct google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_add_reserved_range(google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_EnumDescriptorProto_EnumReservedRange* sub = (struct google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE upb_StringView* google_protobuf_EnumDescriptorProto_mutable_reserved_name(google_protobuf_EnumDescriptorProto *msg, size_t *len) { +UPB_INLINE upb_StringView* google_protobuf_EnumDescriptorProto_mutable_reserved_name(google_protobuf_EnumDescriptorProto* msg, size_t* len) { return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); } -UPB_INLINE upb_StringView* google_protobuf_EnumDescriptorProto_resize_reserved_name(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE upb_StringView* google_protobuf_EnumDescriptorProto_resize_reserved_name(google_protobuf_EnumDescriptorProto* msg, size_t len, upb_Arena* arena) { return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(3, 4), arena); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_add_reserved_name(google_protobuf_EnumDescriptorProto *msg, upb_StringView val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(3, 4), &val, - arena); +UPB_INLINE bool google_protobuf_EnumDescriptorProto_add_reserved_name(google_protobuf_EnumDescriptorProto* msg, upb_StringView val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(3, 4), &val, arena); } /* google.protobuf.EnumDescriptorProto.EnumReservedRange */ UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_EnumReservedRange_new(upb_Arena* arena) { - return (google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena); + return (google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init, arena); } UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_EnumReservedRange_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_EnumDescriptorProto_EnumReservedRange* ret = google_protobuf_EnumDescriptorProto_EnumReservedRange_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3304,24 +3756,40 @@ UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobu int options, upb_Arena* arena) { google_protobuf_EnumDescriptorProto_EnumReservedRange* ret = google_protobuf_EnumDescriptorProto_EnumReservedRange_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize_ex(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_clear_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_clear_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } @@ -3338,12 +3806,12 @@ UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_end(go /* google.protobuf.EnumValueDescriptorProto */ UPB_INLINE google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumValueDescriptorProto_new(upb_Arena* arena) { - return (google_protobuf_EnumValueDescriptorProto*)_upb_Message_New(&google_protobuf_EnumValueDescriptorProto_msginit, arena); + return (google_protobuf_EnumValueDescriptorProto*)_upb_Message_New(&google_protobuf_EnumValueDescriptorProto_msg_init, arena); } UPB_INLINE google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumValueDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_EnumValueDescriptorProto* ret = google_protobuf_EnumValueDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueDescriptorProto_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3353,28 +3821,50 @@ UPB_INLINE google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumValueDe int options, upb_Arena* arena) { google_protobuf_EnumValueDescriptorProto* ret = google_protobuf_EnumValueDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueDescriptorProto_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueDescriptorProto_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_EnumValueDescriptorProto_serialize(const google_protobuf_EnumValueDescriptorProto* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumValueDescriptorProto_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumValueDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_EnumValueDescriptorProto_serialize_ex(const google_protobuf_EnumValueDescriptorProto* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumValueDescriptorProto_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumValueDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_name(const google_protobuf_EnumValueDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_name(const google_protobuf_EnumValueDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_name(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE upb_StringView google_protobuf_EnumValueDescriptorProto_name(const google_protobuf_EnumValueDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_number(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_number(const google_protobuf_EnumValueDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_number(const google_protobuf_EnumValueDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE int32_t google_protobuf_EnumValueDescriptorProto_number(const google_protobuf_EnumValueDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_options(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_options(const google_protobuf_EnumValueDescriptorProto* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_options(const google_protobuf_EnumValueDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 24), const upb_Message*) = NULL; + _upb_clearhas(msg, 3); +} UPB_INLINE const google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_options(const google_protobuf_EnumValueDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 24), const google_protobuf_EnumValueOptions*); } @@ -3391,10 +3881,10 @@ UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_options(google_prot _upb_sethas(msg, 3); *UPB_PTR_AT(msg, UPB_SIZE(16, 24), google_protobuf_EnumValueOptions*) = value; } -UPB_INLINE struct google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_mutable_options(google_protobuf_EnumValueDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_mutable_options(google_protobuf_EnumValueDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumValueOptions* sub = (struct google_protobuf_EnumValueOptions*)google_protobuf_EnumValueDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_EnumValueOptions*)_upb_Message_New(&google_protobuf_EnumValueOptions_msginit, arena); + sub = (struct google_protobuf_EnumValueOptions*)_upb_Message_New(&google_protobuf_EnumValueOptions_msg_init, arena); if (!sub) return NULL; google_protobuf_EnumValueDescriptorProto_set_options(msg, sub); } @@ -3404,12 +3894,12 @@ UPB_INLINE struct google_protobuf_EnumValueOptions* google_protobuf_EnumValueDes /* google.protobuf.ServiceDescriptorProto */ UPB_INLINE google_protobuf_ServiceDescriptorProto* google_protobuf_ServiceDescriptorProto_new(upb_Arena* arena) { - return (google_protobuf_ServiceDescriptorProto*)_upb_Message_New(&google_protobuf_ServiceDescriptorProto_msginit, arena); + return (google_protobuf_ServiceDescriptorProto*)_upb_Message_New(&google_protobuf_ServiceDescriptorProto_msg_init, arena); } UPB_INLINE google_protobuf_ServiceDescriptorProto* google_protobuf_ServiceDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_ServiceDescriptorProto* ret = google_protobuf_ServiceDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_ServiceDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_ServiceDescriptorProto_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3419,55 +3909,77 @@ UPB_INLINE google_protobuf_ServiceDescriptorProto* google_protobuf_ServiceDescri int options, upb_Arena* arena) { google_protobuf_ServiceDescriptorProto* ret = google_protobuf_ServiceDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_ServiceDescriptorProto_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_ServiceDescriptorProto_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_ServiceDescriptorProto_serialize(const google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_ServiceDescriptorProto_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_ServiceDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_ServiceDescriptorProto_serialize_ex(const google_protobuf_ServiceDescriptorProto* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_ServiceDescriptorProto_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_ServiceDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_name(const google_protobuf_ServiceDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_name(const google_protobuf_ServiceDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_name(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE upb_StringView google_protobuf_ServiceDescriptorProto_name(const google_protobuf_ServiceDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_method(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); } -UPB_INLINE const google_protobuf_MethodDescriptorProto* const* google_protobuf_ServiceDescriptorProto_method(const google_protobuf_ServiceDescriptorProto *msg, size_t *len) { return (const google_protobuf_MethodDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); } -UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_options(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_method(const google_protobuf_ServiceDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 24)); +} +UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_method(const google_protobuf_ServiceDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(12, 24)); +} +UPB_INLINE const google_protobuf_MethodDescriptorProto* const* google_protobuf_ServiceDescriptorProto_method(const google_protobuf_ServiceDescriptorProto* msg, size_t* len) { + return (const google_protobuf_MethodDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(12, 24), len); +} +UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_options(const google_protobuf_ServiceDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_options(const google_protobuf_ServiceDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const upb_Message*) = NULL; + _upb_clearhas(msg, 2); +} UPB_INLINE const google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_options(const google_protobuf_ServiceDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_ServiceOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const google_protobuf_ServiceOptions*); } UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_name(google_protobuf_ServiceDescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 1); *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; } -UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_mutable_method(google_protobuf_ServiceDescriptorProto *msg, size_t *len) { - return (google_protobuf_MethodDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); +UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_mutable_method(google_protobuf_ServiceDescriptorProto* msg, size_t* len) { + return (google_protobuf_MethodDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 24), len); } -UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_resize_method(google_protobuf_ServiceDescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_MethodDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_resize_method(google_protobuf_ServiceDescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_MethodDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 24), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_MethodDescriptorProto* google_protobuf_ServiceDescriptorProto_add_method(google_protobuf_ServiceDescriptorProto *msg, upb_Arena *arena) { - struct google_protobuf_MethodDescriptorProto* sub = (struct google_protobuf_MethodDescriptorProto*)_upb_Message_New(&google_protobuf_MethodDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_MethodDescriptorProto* google_protobuf_ServiceDescriptorProto_add_method(google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_MethodDescriptorProto* sub = (struct google_protobuf_MethodDescriptorProto*)_upb_Message_New(&google_protobuf_MethodDescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(12, 24), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_options(google_protobuf_ServiceDescriptorProto *msg, google_protobuf_ServiceOptions* value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_ServiceOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), google_protobuf_ServiceOptions*) = value; } -UPB_INLINE struct google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_mutable_options(google_protobuf_ServiceDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_mutable_options(google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_ServiceOptions* sub = (struct google_protobuf_ServiceOptions*)google_protobuf_ServiceDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_ServiceOptions*)_upb_Message_New(&google_protobuf_ServiceOptions_msginit, arena); + sub = (struct google_protobuf_ServiceOptions*)_upb_Message_New(&google_protobuf_ServiceOptions_msg_init, arena); if (!sub) return NULL; google_protobuf_ServiceDescriptorProto_set_options(msg, sub); } @@ -3477,12 +3989,12 @@ UPB_INLINE struct google_protobuf_ServiceOptions* google_protobuf_ServiceDescrip /* google.protobuf.MethodDescriptorProto */ UPB_INLINE google_protobuf_MethodDescriptorProto* google_protobuf_MethodDescriptorProto_new(upb_Arena* arena) { - return (google_protobuf_MethodDescriptorProto*)_upb_Message_New(&google_protobuf_MethodDescriptorProto_msginit, arena); + return (google_protobuf_MethodDescriptorProto*)_upb_Message_New(&google_protobuf_MethodDescriptorProto_msg_init, arena); } UPB_INLINE google_protobuf_MethodDescriptorProto* google_protobuf_MethodDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_MethodDescriptorProto* ret = google_protobuf_MethodDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_MethodDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_MethodDescriptorProto_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3492,40 +4004,80 @@ UPB_INLINE google_protobuf_MethodDescriptorProto* google_protobuf_MethodDescript int options, upb_Arena* arena) { google_protobuf_MethodDescriptorProto* ret = google_protobuf_MethodDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_MethodDescriptorProto_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_MethodDescriptorProto_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_MethodDescriptorProto_serialize(const google_protobuf_MethodDescriptorProto* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_MethodDescriptorProto_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_MethodDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_MethodDescriptorProto_serialize_ex(const google_protobuf_MethodDescriptorProto* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_MethodDescriptorProto_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_MethodDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_name(const google_protobuf_MethodDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_name(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_name(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_name(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_input_type(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_input_type(const google_protobuf_MethodDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_input_type(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_input_type(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_output_type(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_output_type(const google_protobuf_MethodDescriptorProto* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_output_type(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 3); +} UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_output_type(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_options(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_options(const google_protobuf_MethodDescriptorProto* msg) { + return _upb_hasbit(msg, 4); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_options(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const upb_Message*) = NULL; + _upb_clearhas(msg, 4); +} UPB_INLINE const google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_options(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const google_protobuf_MethodOptions*); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_client_streaming(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { + return _upb_hasbit(msg, 5); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 5); +} UPB_INLINE bool google_protobuf_MethodDescriptorProto_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_server_streaming(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 6); } +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { + return _upb_hasbit(msg, 6); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = 0; + _upb_clearhas(msg, 6); +} UPB_INLINE bool google_protobuf_MethodDescriptorProto_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); } @@ -3546,10 +4098,10 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_set_options(google_protobu _upb_sethas(msg, 4); *UPB_PTR_AT(msg, UPB_SIZE(28, 56), google_protobuf_MethodOptions*) = value; } -UPB_INLINE struct google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_mutable_options(google_protobuf_MethodDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_mutable_options(google_protobuf_MethodDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_MethodOptions* sub = (struct google_protobuf_MethodOptions*)google_protobuf_MethodDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_MethodOptions*)_upb_Message_New(&google_protobuf_MethodOptions_msginit, arena); + sub = (struct google_protobuf_MethodOptions*)_upb_Message_New(&google_protobuf_MethodOptions_msg_init, arena); if (!sub) return NULL; google_protobuf_MethodDescriptorProto_set_options(msg, sub); } @@ -3567,12 +4119,12 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_set_server_streaming(googl /* google.protobuf.FileOptions */ UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_new(upb_Arena* arena) { - return (google_protobuf_FileOptions*)_upb_Message_New(&google_protobuf_FileOptions_msginit, arena); + return (google_protobuf_FileOptions*)_upb_Message_New(&google_protobuf_FileOptions_msg_init, arena); } UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_FileOptions* ret = google_protobuf_FileOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FileOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_FileOptions_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3582,101 +4134,232 @@ UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_parse_ex(con int options, upb_Arena* arena) { google_protobuf_FileOptions* ret = google_protobuf_FileOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FileOptions_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_FileOptions_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_FileOptions_serialize(const google_protobuf_FileOptions* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FileOptions_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FileOptions_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_FileOptions_serialize_ex(const google_protobuf_FileOptions* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FileOptions_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FileOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_FileOptions_has_java_package(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_package(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_package(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE upb_StringView google_protobuf_FileOptions_java_package(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_outer_classname(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_FileOptions_has_java_outer_classname(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_outer_classname(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(28, 40), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_java_outer_classname(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 40), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_optimize_for(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_FileOptions_has_optimize_for(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_FileOptions_clear_optimize_for(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 3); +} UPB_INLINE int32_t google_protobuf_FileOptions_optimize_for(const google_protobuf_FileOptions* msg) { return google_protobuf_FileOptions_has_optimize_for(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) : 1; } -UPB_INLINE bool google_protobuf_FileOptions_has_java_multiple_files(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE bool google_protobuf_FileOptions_has_java_multiple_files(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 4); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_multiple_files(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = 0; + _upb_clearhas(msg, 4); +} UPB_INLINE bool google_protobuf_FileOptions_java_multiple_files(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_go_package(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE bool google_protobuf_FileOptions_has_go_package(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 5); +} +UPB_INLINE void google_protobuf_FileOptions_clear_go_package(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(36, 56), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 5); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_go_package(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(36, 56), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_cc_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 6); } +UPB_INLINE bool google_protobuf_FileOptions_has_cc_generic_services(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 6); +} +UPB_INLINE void google_protobuf_FileOptions_clear_cc_generic_services(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool) = 0; + _upb_clearhas(msg, 6); +} UPB_INLINE bool google_protobuf_FileOptions_cc_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 7); } +UPB_INLINE bool google_protobuf_FileOptions_has_java_generic_services(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 7); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_generic_services(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool) = 0; + _upb_clearhas(msg, 7); +} UPB_INLINE bool google_protobuf_FileOptions_java_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_py_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 8); } +UPB_INLINE bool google_protobuf_FileOptions_has_py_generic_services(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 8); +} +UPB_INLINE void google_protobuf_FileOptions_clear_py_generic_services(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(11, 11), bool) = 0; + _upb_clearhas(msg, 8); +} UPB_INLINE bool google_protobuf_FileOptions_py_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(11, 11), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_generate_equals_and_hash(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 9); } +UPB_INLINE bool google_protobuf_FileOptions_has_java_generate_equals_and_hash(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 9); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_generate_equals_and_hash(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool) = 0; + _upb_clearhas(msg, 9); +} UPB_INLINE bool google_protobuf_FileOptions_java_generate_equals_and_hash(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_deprecated(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 10); } +UPB_INLINE bool google_protobuf_FileOptions_has_deprecated(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 10); +} +UPB_INLINE void google_protobuf_FileOptions_clear_deprecated(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool) = 0; + _upb_clearhas(msg, 10); +} UPB_INLINE bool google_protobuf_FileOptions_deprecated(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_string_check_utf8(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 11); } +UPB_INLINE bool google_protobuf_FileOptions_has_java_string_check_utf8(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 11); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_string_check_utf8(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool) = 0; + _upb_clearhas(msg, 11); +} UPB_INLINE bool google_protobuf_FileOptions_java_string_check_utf8(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_cc_enable_arenas(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 12); } +UPB_INLINE bool google_protobuf_FileOptions_has_cc_enable_arenas(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 12); +} +UPB_INLINE void google_protobuf_FileOptions_clear_cc_enable_arenas(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) = 0; + _upb_clearhas(msg, 12); +} UPB_INLINE bool google_protobuf_FileOptions_cc_enable_arenas(const google_protobuf_FileOptions* msg) { return google_protobuf_FileOptions_has_cc_enable_arenas(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) : true; } -UPB_INLINE bool google_protobuf_FileOptions_has_objc_class_prefix(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 13); } +UPB_INLINE bool google_protobuf_FileOptions_has_objc_class_prefix(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 13); +} +UPB_INLINE void google_protobuf_FileOptions_clear_objc_class_prefix(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(44, 72), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 13); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_objc_class_prefix(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(44, 72), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_csharp_namespace(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 14); } +UPB_INLINE bool google_protobuf_FileOptions_has_csharp_namespace(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 14); +} +UPB_INLINE void google_protobuf_FileOptions_clear_csharp_namespace(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(52, 88), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 14); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_csharp_namespace(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(52, 88), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_swift_prefix(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 15); } +UPB_INLINE bool google_protobuf_FileOptions_has_swift_prefix(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 15); +} +UPB_INLINE void google_protobuf_FileOptions_clear_swift_prefix(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(60, 104), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 15); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_swift_prefix(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(60, 104), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_php_class_prefix(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 16); } +UPB_INLINE bool google_protobuf_FileOptions_has_php_class_prefix(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 16); +} +UPB_INLINE void google_protobuf_FileOptions_clear_php_class_prefix(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(68, 120), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 16); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_php_class_prefix(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(68, 120), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_php_namespace(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 17); } +UPB_INLINE bool google_protobuf_FileOptions_has_php_namespace(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 17); +} +UPB_INLINE void google_protobuf_FileOptions_clear_php_namespace(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(76, 136), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 17); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_php_namespace(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(76, 136), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_php_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 18); } +UPB_INLINE bool google_protobuf_FileOptions_has_php_generic_services(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 18); +} +UPB_INLINE void google_protobuf_FileOptions_clear_php_generic_services(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = 0; + _upb_clearhas(msg, 18); +} UPB_INLINE bool google_protobuf_FileOptions_php_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_php_metadata_namespace(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 19); } +UPB_INLINE bool google_protobuf_FileOptions_has_php_metadata_namespace(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 19); +} +UPB_INLINE void google_protobuf_FileOptions_clear_php_metadata_namespace(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(84, 152), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 19); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_php_metadata_namespace(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(84, 152), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_ruby_package(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 20); } +UPB_INLINE bool google_protobuf_FileOptions_has_ruby_package(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 20); +} +UPB_INLINE void google_protobuf_FileOptions_clear_ruby_package(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(92, 168), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 20); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_ruby_package(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(92, 168), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_uninterpreted_option(const google_protobuf_FileOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(100, 184)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FileOptions_uninterpreted_option(const google_protobuf_FileOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(100, 184), len); } +UPB_INLINE bool google_protobuf_FileOptions_has_uninterpreted_option(const google_protobuf_FileOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(100, 184)); +} +UPB_INLINE void google_protobuf_FileOptions_clear_uninterpreted_option(const google_protobuf_FileOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(100, 184)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FileOptions_uninterpreted_option(const google_protobuf_FileOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(100, 184), len); +} UPB_INLINE void google_protobuf_FileOptions_set_java_package(google_protobuf_FileOptions *msg, upb_StringView value) { _upb_sethas(msg, 1); @@ -3758,16 +4441,15 @@ UPB_INLINE void google_protobuf_FileOptions_set_ruby_package(google_protobuf_Fil _upb_sethas(msg, 20); *UPB_PTR_AT(msg, UPB_SIZE(92, 168), upb_StringView) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_mutable_uninterpreted_option(google_protobuf_FileOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_mutable_uninterpreted_option(google_protobuf_FileOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(100, 184), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_resize_uninterpreted_option(google_protobuf_FileOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_resize_uninterpreted_option(google_protobuf_FileOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(100, 184), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FileOptions_add_uninterpreted_option(google_protobuf_FileOptions *msg, upb_Arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(100, 184), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FileOptions_add_uninterpreted_option(google_protobuf_FileOptions* msg, upb_Arena* arena) { + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(100, 184), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -3775,12 +4457,12 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FileOptio /* google.protobuf.MessageOptions */ UPB_INLINE google_protobuf_MessageOptions* google_protobuf_MessageOptions_new(upb_Arena* arena) { - return (google_protobuf_MessageOptions*)_upb_Message_New(&google_protobuf_MessageOptions_msginit, arena); + return (google_protobuf_MessageOptions*)_upb_Message_New(&google_protobuf_MessageOptions_msg_init, arena); } UPB_INLINE google_protobuf_MessageOptions* google_protobuf_MessageOptions_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_MessageOptions* ret = google_protobuf_MessageOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_MessageOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_MessageOptions_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3790,37 +4472,72 @@ UPB_INLINE google_protobuf_MessageOptions* google_protobuf_MessageOptions_parse_ int options, upb_Arena* arena) { google_protobuf_MessageOptions* ret = google_protobuf_MessageOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_MessageOptions_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_MessageOptions_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_MessageOptions_serialize(const google_protobuf_MessageOptions* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_MessageOptions_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_MessageOptions_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_MessageOptions_serialize_ex(const google_protobuf_MessageOptions* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_MessageOptions_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_MessageOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_MessageOptions_has_message_set_wire_format(const google_protobuf_MessageOptions* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_message_set_wire_format(const google_protobuf_MessageOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_MessageOptions_has_message_set_wire_format(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE bool google_protobuf_MessageOptions_message_set_wire_format(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_MessageOptions_has_no_standard_descriptor_accessor(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_MessageOptions_has_no_standard_descriptor_accessor(const google_protobuf_MessageOptions* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_no_standard_descriptor_accessor(const google_protobuf_MessageOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE bool google_protobuf_MessageOptions_no_standard_descriptor_accessor(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); } -UPB_INLINE bool google_protobuf_MessageOptions_has_deprecated(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_MessageOptions_has_deprecated(const google_protobuf_MessageOptions* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_deprecated(const google_protobuf_MessageOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool) = 0; + _upb_clearhas(msg, 3); +} UPB_INLINE bool google_protobuf_MessageOptions_deprecated(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool); } -UPB_INLINE bool google_protobuf_MessageOptions_has_map_entry(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE bool google_protobuf_MessageOptions_has_map_entry(const google_protobuf_MessageOptions* msg) { + return _upb_hasbit(msg, 4); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_map_entry(const google_protobuf_MessageOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), bool) = 0; + _upb_clearhas(msg, 4); +} UPB_INLINE bool google_protobuf_MessageOptions_map_entry(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), bool); } -UPB_INLINE bool google_protobuf_MessageOptions_has_uninterpreted_option(const google_protobuf_MessageOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 8)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MessageOptions_uninterpreted_option(const google_protobuf_MessageOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(8, 8), len); } +UPB_INLINE bool google_protobuf_MessageOptions_has_uninterpreted_option(const google_protobuf_MessageOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 8)); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_uninterpreted_option(const google_protobuf_MessageOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(8, 8)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MessageOptions_uninterpreted_option(const google_protobuf_MessageOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(8, 8), len); +} UPB_INLINE void google_protobuf_MessageOptions_set_message_set_wire_format(google_protobuf_MessageOptions *msg, bool value) { _upb_sethas(msg, 1); @@ -3838,16 +4555,15 @@ UPB_INLINE void google_protobuf_MessageOptions_set_map_entry(google_protobuf_Mes _upb_sethas(msg, 4); *UPB_PTR_AT(msg, UPB_SIZE(4, 4), bool) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_mutable_uninterpreted_option(google_protobuf_MessageOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_mutable_uninterpreted_option(google_protobuf_MessageOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 8), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_resize_uninterpreted_option(google_protobuf_MessageOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_resize_uninterpreted_option(google_protobuf_MessageOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(8, 8), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MessageOptions_add_uninterpreted_option(google_protobuf_MessageOptions *msg, upb_Arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(8, 8), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MessageOptions_add_uninterpreted_option(google_protobuf_MessageOptions* msg, upb_Arena* arena) { + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(8, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -3855,12 +4571,12 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MessageOp /* google.protobuf.FieldOptions */ UPB_INLINE google_protobuf_FieldOptions* google_protobuf_FieldOptions_new(upb_Arena* arena) { - return (google_protobuf_FieldOptions*)_upb_Message_New(&google_protobuf_FieldOptions_msginit, arena); + return (google_protobuf_FieldOptions*)_upb_Message_New(&google_protobuf_FieldOptions_msg_init, arena); } UPB_INLINE google_protobuf_FieldOptions* google_protobuf_FieldOptions_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_FieldOptions* ret = google_protobuf_FieldOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FieldOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_FieldOptions_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3870,49 +4586,102 @@ UPB_INLINE google_protobuf_FieldOptions* google_protobuf_FieldOptions_parse_ex(c int options, upb_Arena* arena) { google_protobuf_FieldOptions* ret = google_protobuf_FieldOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FieldOptions_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_FieldOptions_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_FieldOptions_serialize(const google_protobuf_FieldOptions* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FieldOptions_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FieldOptions_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_FieldOptions_serialize_ex(const google_protobuf_FieldOptions* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FieldOptions_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FieldOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_ctype(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_ctype(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_FieldOptions_has_ctype(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE int32_t google_protobuf_FieldOptions_ctype(const google_protobuf_FieldOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_FieldOptions_has_packed(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_FieldOptions_has_packed(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_packed(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE bool google_protobuf_FieldOptions_packed(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool); +} +UPB_INLINE bool google_protobuf_FieldOptions_has_deprecated(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_deprecated(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool) = 0; + _upb_clearhas(msg, 3); } -UPB_INLINE bool google_protobuf_FieldOptions_has_deprecated(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 3); } UPB_INLINE bool google_protobuf_FieldOptions_deprecated(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool); +} +UPB_INLINE bool google_protobuf_FieldOptions_has_lazy(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 4); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_lazy(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool) = 0; + _upb_clearhas(msg, 4); } -UPB_INLINE bool google_protobuf_FieldOptions_has_lazy(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 4); } UPB_INLINE bool google_protobuf_FieldOptions_lazy(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool); +} +UPB_INLINE bool google_protobuf_FieldOptions_has_jstype(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 5); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_jstype(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = 0; + _upb_clearhas(msg, 5); } -UPB_INLINE bool google_protobuf_FieldOptions_has_jstype(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 5); } UPB_INLINE int32_t google_protobuf_FieldOptions_jstype(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); + return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t); +} +UPB_INLINE bool google_protobuf_FieldOptions_has_weak(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 6); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_weak(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = 0; + _upb_clearhas(msg, 6); } -UPB_INLINE bool google_protobuf_FieldOptions_has_weak(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 6); } UPB_INLINE bool google_protobuf_FieldOptions_weak(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); +} +UPB_INLINE bool google_protobuf_FieldOptions_has_unverified_lazy(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 7); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_unverified_lazy(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(17, 17), bool) = 0; + _upb_clearhas(msg, 7); } -UPB_INLINE bool google_protobuf_FieldOptions_has_unverified_lazy(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 7); } UPB_INLINE bool google_protobuf_FieldOptions_unverified_lazy(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(17, 17), bool); +} +UPB_INLINE bool google_protobuf_FieldOptions_has_uninterpreted_option(const google_protobuf_FieldOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 24)); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_uninterpreted_option(const google_protobuf_FieldOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(20, 24)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FieldOptions_uninterpreted_option(const google_protobuf_FieldOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(20, 24), len); } -UPB_INLINE bool google_protobuf_FieldOptions_has_uninterpreted_option(const google_protobuf_FieldOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 24)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FieldOptions_uninterpreted_option(const google_protobuf_FieldOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(20, 24), len); } UPB_INLINE void google_protobuf_FieldOptions_set_ctype(google_protobuf_FieldOptions *msg, int32_t value) { _upb_sethas(msg, 1); @@ -3920,38 +4689,37 @@ UPB_INLINE void google_protobuf_FieldOptions_set_ctype(google_protobuf_FieldOpti } UPB_INLINE void google_protobuf_FieldOptions_set_packed(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_deprecated(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_lazy(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_jstype(google_protobuf_FieldOptions *msg, int32_t value) { _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_weak(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 6); - *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_unverified_lazy(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 7); - *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(17, 17), bool) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_mutable_uninterpreted_option(google_protobuf_FieldOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_mutable_uninterpreted_option(google_protobuf_FieldOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 24), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_resize_uninterpreted_option(google_protobuf_FieldOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_resize_uninterpreted_option(google_protobuf_FieldOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 24), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FieldOptions_add_uninterpreted_option(google_protobuf_FieldOptions *msg, upb_Arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(20, 24), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FieldOptions_add_uninterpreted_option(google_protobuf_FieldOptions* msg, upb_Arena* arena) { + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 24), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -3959,12 +4727,12 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FieldOpti /* google.protobuf.OneofOptions */ UPB_INLINE google_protobuf_OneofOptions* google_protobuf_OneofOptions_new(upb_Arena* arena) { - return (google_protobuf_OneofOptions*)_upb_Message_New(&google_protobuf_OneofOptions_msginit, arena); + return (google_protobuf_OneofOptions*)_upb_Message_New(&google_protobuf_OneofOptions_msg_init, arena); } UPB_INLINE google_protobuf_OneofOptions* google_protobuf_OneofOptions_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_OneofOptions* ret = google_protobuf_OneofOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_OneofOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_OneofOptions_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3974,32 +4742,42 @@ UPB_INLINE google_protobuf_OneofOptions* google_protobuf_OneofOptions_parse_ex(c int options, upb_Arena* arena) { google_protobuf_OneofOptions* ret = google_protobuf_OneofOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_OneofOptions_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_OneofOptions_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_OneofOptions_serialize(const google_protobuf_OneofOptions* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_OneofOptions_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_OneofOptions_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_OneofOptions_serialize_ex(const google_protobuf_OneofOptions* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_OneofOptions_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_OneofOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_OneofOptions_has_uninterpreted_option(const google_protobuf_OneofOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE void google_protobuf_OneofOptions_clear_uninterpreted_option(const google_protobuf_OneofOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_OneofOptions_uninterpreted_option(const google_protobuf_OneofOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE bool google_protobuf_OneofOptions_has_uninterpreted_option(const google_protobuf_OneofOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_OneofOptions_uninterpreted_option(const google_protobuf_OneofOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_mutable_uninterpreted_option(google_protobuf_OneofOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_mutable_uninterpreted_option(google_protobuf_OneofOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_resize_uninterpreted_option(google_protobuf_OneofOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_resize_uninterpreted_option(google_protobuf_OneofOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_OneofOptions_add_uninterpreted_option(google_protobuf_OneofOptions *msg, upb_Arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_OneofOptions_add_uninterpreted_option(google_protobuf_OneofOptions* msg, upb_Arena* arena) { + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4007,12 +4785,12 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_OneofOpti /* google.protobuf.EnumOptions */ UPB_INLINE google_protobuf_EnumOptions* google_protobuf_EnumOptions_new(upb_Arena* arena) { - return (google_protobuf_EnumOptions*)_upb_Message_New(&google_protobuf_EnumOptions_msginit, arena); + return (google_protobuf_EnumOptions*)_upb_Message_New(&google_protobuf_EnumOptions_msg_init, arena); } UPB_INLINE google_protobuf_EnumOptions* google_protobuf_EnumOptions_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_EnumOptions* ret = google_protobuf_EnumOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_EnumOptions_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -4022,31 +4800,54 @@ UPB_INLINE google_protobuf_EnumOptions* google_protobuf_EnumOptions_parse_ex(con int options, upb_Arena* arena) { google_protobuf_EnumOptions* ret = google_protobuf_EnumOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumOptions_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_EnumOptions_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_EnumOptions_serialize(const google_protobuf_EnumOptions* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumOptions_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumOptions_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_EnumOptions_serialize_ex(const google_protobuf_EnumOptions* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumOptions_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_EnumOptions_has_allow_alias(const google_protobuf_EnumOptions* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_EnumOptions_clear_allow_alias(const google_protobuf_EnumOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_EnumOptions_has_allow_alias(const google_protobuf_EnumOptions *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE bool google_protobuf_EnumOptions_allow_alias(const google_protobuf_EnumOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_EnumOptions_has_deprecated(const google_protobuf_EnumOptions *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_EnumOptions_has_deprecated(const google_protobuf_EnumOptions* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_EnumOptions_clear_deprecated(const google_protobuf_EnumOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE bool google_protobuf_EnumOptions_deprecated(const google_protobuf_EnumOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); } -UPB_INLINE bool google_protobuf_EnumOptions_has_uninterpreted_option(const google_protobuf_EnumOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumOptions_uninterpreted_option(const google_protobuf_EnumOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } - -UPB_INLINE void google_protobuf_EnumOptions_set_allow_alias(google_protobuf_EnumOptions *msg, bool value) { +UPB_INLINE bool google_protobuf_EnumOptions_has_uninterpreted_option(const google_protobuf_EnumOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE void google_protobuf_EnumOptions_clear_uninterpreted_option(const google_protobuf_EnumOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumOptions_uninterpreted_option(const google_protobuf_EnumOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); +} + +UPB_INLINE void google_protobuf_EnumOptions_set_allow_alias(google_protobuf_EnumOptions *msg, bool value) { _upb_sethas(msg, 1); *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; } @@ -4054,16 +4855,15 @@ UPB_INLINE void google_protobuf_EnumOptions_set_deprecated(google_protobuf_EnumO _upb_sethas(msg, 2); *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_mutable_uninterpreted_option(google_protobuf_EnumOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_mutable_uninterpreted_option(google_protobuf_EnumOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_resize_uninterpreted_option(google_protobuf_EnumOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_resize_uninterpreted_option(google_protobuf_EnumOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumOptions_add_uninterpreted_option(google_protobuf_EnumOptions *msg, upb_Arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumOptions_add_uninterpreted_option(google_protobuf_EnumOptions* msg, upb_Arena* arena) { + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4071,12 +4871,12 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumOptio /* google.protobuf.EnumValueOptions */ UPB_INLINE google_protobuf_EnumValueOptions* google_protobuf_EnumValueOptions_new(upb_Arena* arena) { - return (google_protobuf_EnumValueOptions*)_upb_Message_New(&google_protobuf_EnumValueOptions_msginit, arena); + return (google_protobuf_EnumValueOptions*)_upb_Message_New(&google_protobuf_EnumValueOptions_msg_init, arena); } UPB_INLINE google_protobuf_EnumValueOptions* google_protobuf_EnumValueOptions_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_EnumValueOptions* ret = google_protobuf_EnumValueOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueOptions_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -4086,40 +4886,56 @@ UPB_INLINE google_protobuf_EnumValueOptions* google_protobuf_EnumValueOptions_pa int options, upb_Arena* arena) { google_protobuf_EnumValueOptions* ret = google_protobuf_EnumValueOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueOptions_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueOptions_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_EnumValueOptions_serialize(const google_protobuf_EnumValueOptions* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumValueOptions_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumValueOptions_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_EnumValueOptions_serialize_ex(const google_protobuf_EnumValueOptions* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumValueOptions_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumValueOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_EnumValueOptions_has_deprecated(const google_protobuf_EnumValueOptions* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_EnumValueOptions_clear_deprecated(const google_protobuf_EnumValueOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_EnumValueOptions_has_deprecated(const google_protobuf_EnumValueOptions *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE bool google_protobuf_EnumValueOptions_deprecated(const google_protobuf_EnumValueOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_EnumValueOptions_has_uninterpreted_option(const google_protobuf_EnumValueOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumValueOptions_uninterpreted_option(const google_protobuf_EnumValueOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } +UPB_INLINE bool google_protobuf_EnumValueOptions_has_uninterpreted_option(const google_protobuf_EnumValueOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE void google_protobuf_EnumValueOptions_clear_uninterpreted_option(const google_protobuf_EnumValueOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumValueOptions_uninterpreted_option(const google_protobuf_EnumValueOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); +} UPB_INLINE void google_protobuf_EnumValueOptions_set_deprecated(google_protobuf_EnumValueOptions *msg, bool value) { _upb_sethas(msg, 1); *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_mutable_uninterpreted_option(google_protobuf_EnumValueOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_mutable_uninterpreted_option(google_protobuf_EnumValueOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_resize_uninterpreted_option(google_protobuf_EnumValueOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_resize_uninterpreted_option(google_protobuf_EnumValueOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumValueOptions_add_uninterpreted_option(google_protobuf_EnumValueOptions *msg, upb_Arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumValueOptions_add_uninterpreted_option(google_protobuf_EnumValueOptions* msg, upb_Arena* arena) { + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4127,12 +4943,12 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumValue /* google.protobuf.ServiceOptions */ UPB_INLINE google_protobuf_ServiceOptions* google_protobuf_ServiceOptions_new(upb_Arena* arena) { - return (google_protobuf_ServiceOptions*)_upb_Message_New(&google_protobuf_ServiceOptions_msginit, arena); + return (google_protobuf_ServiceOptions*)_upb_Message_New(&google_protobuf_ServiceOptions_msg_init, arena); } UPB_INLINE google_protobuf_ServiceOptions* google_protobuf_ServiceOptions_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_ServiceOptions* ret = google_protobuf_ServiceOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_ServiceOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_ServiceOptions_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -4142,40 +4958,56 @@ UPB_INLINE google_protobuf_ServiceOptions* google_protobuf_ServiceOptions_parse_ int options, upb_Arena* arena) { google_protobuf_ServiceOptions* ret = google_protobuf_ServiceOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_ServiceOptions_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_ServiceOptions_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_ServiceOptions_serialize(const google_protobuf_ServiceOptions* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_ServiceOptions_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_ServiceOptions_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_ServiceOptions_serialize_ex(const google_protobuf_ServiceOptions* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_ServiceOptions_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_ServiceOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_ServiceOptions_has_deprecated(const google_protobuf_ServiceOptions* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_ServiceOptions_clear_deprecated(const google_protobuf_ServiceOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_ServiceOptions_has_deprecated(const google_protobuf_ServiceOptions *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE bool google_protobuf_ServiceOptions_deprecated(const google_protobuf_ServiceOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_ServiceOptions_has_uninterpreted_option(const google_protobuf_ServiceOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ServiceOptions_uninterpreted_option(const google_protobuf_ServiceOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } +UPB_INLINE bool google_protobuf_ServiceOptions_has_uninterpreted_option(const google_protobuf_ServiceOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE void google_protobuf_ServiceOptions_clear_uninterpreted_option(const google_protobuf_ServiceOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ServiceOptions_uninterpreted_option(const google_protobuf_ServiceOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); +} UPB_INLINE void google_protobuf_ServiceOptions_set_deprecated(google_protobuf_ServiceOptions *msg, bool value) { _upb_sethas(msg, 1); *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_mutable_uninterpreted_option(google_protobuf_ServiceOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_mutable_uninterpreted_option(google_protobuf_ServiceOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_resize_uninterpreted_option(google_protobuf_ServiceOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_resize_uninterpreted_option(google_protobuf_ServiceOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ServiceOptions_add_uninterpreted_option(google_protobuf_ServiceOptions *msg, upb_Arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ServiceOptions_add_uninterpreted_option(google_protobuf_ServiceOptions* msg, upb_Arena* arena) { + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4183,12 +5015,12 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ServiceOp /* google.protobuf.MethodOptions */ UPB_INLINE google_protobuf_MethodOptions* google_protobuf_MethodOptions_new(upb_Arena* arena) { - return (google_protobuf_MethodOptions*)_upb_Message_New(&google_protobuf_MethodOptions_msginit, arena); + return (google_protobuf_MethodOptions*)_upb_Message_New(&google_protobuf_MethodOptions_msg_init, arena); } UPB_INLINE google_protobuf_MethodOptions* google_protobuf_MethodOptions_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_MethodOptions* ret = google_protobuf_MethodOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_MethodOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_MethodOptions_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -4198,48 +5030,70 @@ UPB_INLINE google_protobuf_MethodOptions* google_protobuf_MethodOptions_parse_ex int options, upb_Arena* arena) { google_protobuf_MethodOptions* ret = google_protobuf_MethodOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_MethodOptions_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_MethodOptions_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_MethodOptions_serialize(const google_protobuf_MethodOptions* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_MethodOptions_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_MethodOptions_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_MethodOptions_serialize_ex(const google_protobuf_MethodOptions* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_MethodOptions_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_MethodOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_MethodOptions_has_deprecated(const google_protobuf_MethodOptions* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_MethodOptions_clear_deprecated(const google_protobuf_MethodOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_MethodOptions_has_deprecated(const google_protobuf_MethodOptions *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE bool google_protobuf_MethodOptions_deprecated(const google_protobuf_MethodOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); +} +UPB_INLINE bool google_protobuf_MethodOptions_has_idempotency_level(const google_protobuf_MethodOptions* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_MethodOptions_clear_idempotency_level(const google_protobuf_MethodOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 2); } -UPB_INLINE bool google_protobuf_MethodOptions_has_idempotency_level(const google_protobuf_MethodOptions *msg) { return _upb_hasbit(msg, 2); } UPB_INLINE int32_t google_protobuf_MethodOptions_idempotency_level(const google_protobuf_MethodOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_MethodOptions_has_uninterpreted_option(const google_protobuf_MethodOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 16)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MethodOptions_uninterpreted_option(const google_protobuf_MethodOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(12, 16), len); } +UPB_INLINE bool google_protobuf_MethodOptions_has_uninterpreted_option(const google_protobuf_MethodOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 8)); +} +UPB_INLINE void google_protobuf_MethodOptions_clear_uninterpreted_option(const google_protobuf_MethodOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(8, 8)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MethodOptions_uninterpreted_option(const google_protobuf_MethodOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(8, 8), len); +} UPB_INLINE void google_protobuf_MethodOptions_set_deprecated(google_protobuf_MethodOptions *msg, bool value) { _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; } UPB_INLINE void google_protobuf_MethodOptions_set_idempotency_level(google_protobuf_MethodOptions *msg, int32_t value) { _upb_sethas(msg, 2); *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_mutable_uninterpreted_option(google_protobuf_MethodOptions *msg, size_t *len) { - return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 16), len); +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_mutable_uninterpreted_option(google_protobuf_MethodOptions* msg, size_t* len) { + return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 8), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_resize_uninterpreted_option(google_protobuf_MethodOptions *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 16), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_resize_uninterpreted_option(google_protobuf_MethodOptions* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(8, 8), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MethodOptions_add_uninterpreted_option(google_protobuf_MethodOptions *msg, upb_Arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(12, 16), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MethodOptions_add_uninterpreted_option(google_protobuf_MethodOptions* msg, upb_Arena* arena) { + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(8, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4247,12 +5101,12 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MethodOpt /* google.protobuf.UninterpretedOption */ UPB_INLINE google_protobuf_UninterpretedOption* google_protobuf_UninterpretedOption_new(upb_Arena* arena) { - return (google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); + return (google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); } UPB_INLINE google_protobuf_UninterpretedOption* google_protobuf_UninterpretedOption_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_UninterpretedOption* ret = google_protobuf_UninterpretedOption_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -4262,93 +5116,139 @@ UPB_INLINE google_protobuf_UninterpretedOption* google_protobuf_UninterpretedOpt int options, upb_Arena* arena) { google_protobuf_UninterpretedOption* ret = google_protobuf_UninterpretedOption_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_UninterpretedOption_serialize(const google_protobuf_UninterpretedOption* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_UninterpretedOption_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_UninterpretedOption_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_UninterpretedOption_serialize_ex(const google_protobuf_UninterpretedOption* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_UninterpretedOption_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_UninterpretedOption_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_name(const google_protobuf_UninterpretedOption* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_name(const google_protobuf_UninterpretedOption* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE const google_protobuf_UninterpretedOption_NamePart* const* google_protobuf_UninterpretedOption_name(const google_protobuf_UninterpretedOption* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption_NamePart* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_identifier_value(const google_protobuf_UninterpretedOption* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_identifier_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 16), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_name(const google_protobuf_UninterpretedOption *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(56, 80)); } -UPB_INLINE const google_protobuf_UninterpretedOption_NamePart* const* google_protobuf_UninterpretedOption_name(const google_protobuf_UninterpretedOption *msg, size_t *len) { return (const google_protobuf_UninterpretedOption_NamePart* const*)_upb_array_accessor(msg, UPB_SIZE(56, 80), len); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_identifier_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_identifier_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(32, 32), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(8, 16), upb_StringView); +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_positive_int_value(const google_protobuf_UninterpretedOption* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_positive_int_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(32, 64), uint64_t) = 0; + _upb_clearhas(msg, 2); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_positive_int_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 2); } UPB_INLINE uint64_t google_protobuf_UninterpretedOption_positive_int_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), uint64_t); + return *UPB_PTR_AT(msg, UPB_SIZE(32, 64), uint64_t); +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_negative_int_value(const google_protobuf_UninterpretedOption* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_negative_int_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(40, 72), int64_t) = 0; + _upb_clearhas(msg, 3); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_negative_int_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 3); } UPB_INLINE int64_t google_protobuf_UninterpretedOption_negative_int_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int64_t); + return *UPB_PTR_AT(msg, UPB_SIZE(40, 72), int64_t); +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_double_value(const google_protobuf_UninterpretedOption* msg) { + return _upb_hasbit(msg, 4); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_double_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(48, 80), double) = 0; + _upb_clearhas(msg, 4); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_double_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 4); } UPB_INLINE double google_protobuf_UninterpretedOption_double_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), double); + return *UPB_PTR_AT(msg, UPB_SIZE(48, 80), double); +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_string_value(const google_protobuf_UninterpretedOption* msg) { + return _upb_hasbit(msg, 5); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_string_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 5); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_string_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 5); } UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_string_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(40, 48), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), upb_StringView); +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_aggregate_value(const google_protobuf_UninterpretedOption* msg) { + return _upb_hasbit(msg, 6); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_aggregate_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(24, 48), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 6); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_aggregate_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 6); } UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_aggregate_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(48, 64), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(24, 48), upb_StringView); } -UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_mutable_name(google_protobuf_UninterpretedOption *msg, size_t *len) { - return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_mutable_accessor(msg, UPB_SIZE(56, 80), len); +UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_mutable_name(google_protobuf_UninterpretedOption* msg, size_t* len) { + return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); } -UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_resize_name(google_protobuf_UninterpretedOption *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_UninterpretedOption_NamePart**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(56, 80), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_resize_name(google_protobuf_UninterpretedOption* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_UninterpretedOption_NamePart**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_add_name(google_protobuf_UninterpretedOption *msg, upb_Arena *arena) { - struct google_protobuf_UninterpretedOption_NamePart* sub = (struct google_protobuf_UninterpretedOption_NamePart*)_upb_Message_New(&google_protobuf_UninterpretedOption_NamePart_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(56, 80), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_add_name(google_protobuf_UninterpretedOption* msg, upb_Arena* arena) { + struct google_protobuf_UninterpretedOption_NamePart* sub = (struct google_protobuf_UninterpretedOption_NamePart*)_upb_Message_New(&google_protobuf_UninterpretedOption_NamePart_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_UninterpretedOption_set_identifier_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) { _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(32, 32), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(8, 16), upb_StringView) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_positive_int_value(google_protobuf_UninterpretedOption *msg, uint64_t value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), uint64_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(32, 64), uint64_t) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_negative_int_value(google_protobuf_UninterpretedOption *msg, int64_t value) { _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int64_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(40, 72), int64_t) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_double_value(google_protobuf_UninterpretedOption *msg, double value) { _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(24, 24), double) = value; + *UPB_PTR_AT(msg, UPB_SIZE(48, 80), double) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_string_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) { _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(40, 48), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), upb_StringView) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_aggregate_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) { _upb_sethas(msg, 6); - *UPB_PTR_AT(msg, UPB_SIZE(48, 64), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(24, 48), upb_StringView) = value; } /* google.protobuf.UninterpretedOption.NamePart */ UPB_INLINE google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_NamePart_new(upb_Arena* arena) { - return (google_protobuf_UninterpretedOption_NamePart*)_upb_Message_New(&google_protobuf_UninterpretedOption_NamePart_msginit, arena); + return (google_protobuf_UninterpretedOption_NamePart*)_upb_Message_New(&google_protobuf_UninterpretedOption_NamePart_msg_init, arena); } UPB_INLINE google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_NamePart_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_UninterpretedOption_NamePart* ret = google_protobuf_UninterpretedOption_NamePart_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_NamePart_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_NamePart_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -4358,24 +5258,40 @@ UPB_INLINE google_protobuf_UninterpretedOption_NamePart* google_protobuf_Uninter int options, upb_Arena* arena) { google_protobuf_UninterpretedOption_NamePart* ret = google_protobuf_UninterpretedOption_NamePart_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_NamePart_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_NamePart_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_UninterpretedOption_NamePart_serialize(const google_protobuf_UninterpretedOption_NamePart* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_UninterpretedOption_NamePart_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_UninterpretedOption_NamePart_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_UninterpretedOption_NamePart_serialize_ex(const google_protobuf_UninterpretedOption_NamePart* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_UninterpretedOption_NamePart_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_UninterpretedOption_NamePart_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_name_part(const google_protobuf_UninterpretedOption_NamePart* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_clear_name_part(const google_protobuf_UninterpretedOption_NamePart* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); } -UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_name_part(const google_protobuf_UninterpretedOption_NamePart *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_NamePart_name_part(const google_protobuf_UninterpretedOption_NamePart* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_is_extension(const google_protobuf_UninterpretedOption_NamePart *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_is_extension(const google_protobuf_UninterpretedOption_NamePart* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_clear_is_extension(const google_protobuf_UninterpretedOption_NamePart* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_is_extension(const google_protobuf_UninterpretedOption_NamePart* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } @@ -4392,12 +5308,12 @@ UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_is_extension(go /* google.protobuf.SourceCodeInfo */ UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_new(upb_Arena* arena) { - return (google_protobuf_SourceCodeInfo*)_upb_Message_New(&google_protobuf_SourceCodeInfo_msginit, arena); + return (google_protobuf_SourceCodeInfo*)_upb_Message_New(&google_protobuf_SourceCodeInfo_msg_init, arena); } UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_SourceCodeInfo* ret = google_protobuf_SourceCodeInfo_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -4407,32 +5323,42 @@ UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_parse_ int options, upb_Arena* arena) { google_protobuf_SourceCodeInfo* ret = google_protobuf_SourceCodeInfo_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_SourceCodeInfo_serialize(const google_protobuf_SourceCodeInfo* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_SourceCodeInfo_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_SourceCodeInfo_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_SourceCodeInfo_serialize_ex(const google_protobuf_SourceCodeInfo* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_SourceCodeInfo_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_SourceCodeInfo_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_has_location(const google_protobuf_SourceCodeInfo* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_clear_location(const google_protobuf_SourceCodeInfo* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE const google_protobuf_SourceCodeInfo_Location* const* google_protobuf_SourceCodeInfo_location(const google_protobuf_SourceCodeInfo* msg, size_t* len) { + return (const google_protobuf_SourceCodeInfo_Location* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_has_location(const google_protobuf_SourceCodeInfo *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_SourceCodeInfo_Location* const* google_protobuf_SourceCodeInfo_location(const google_protobuf_SourceCodeInfo *msg, size_t *len) { return (const google_protobuf_SourceCodeInfo_Location* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_mutable_location(google_protobuf_SourceCodeInfo *msg, size_t *len) { +UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_mutable_location(google_protobuf_SourceCodeInfo* msg, size_t* len) { return (google_protobuf_SourceCodeInfo_Location**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_resize_location(google_protobuf_SourceCodeInfo *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_resize_location(google_protobuf_SourceCodeInfo* msg, size_t len, upb_Arena* arena) { return (google_protobuf_SourceCodeInfo_Location**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_add_location(google_protobuf_SourceCodeInfo *msg, upb_Arena *arena) { - struct google_protobuf_SourceCodeInfo_Location* sub = (struct google_protobuf_SourceCodeInfo_Location*)_upb_Message_New(&google_protobuf_SourceCodeInfo_Location_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_add_location(google_protobuf_SourceCodeInfo* msg, upb_Arena* arena) { + struct google_protobuf_SourceCodeInfo_Location* sub = (struct google_protobuf_SourceCodeInfo_Location*)_upb_Message_New(&google_protobuf_SourceCodeInfo_Location_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4440,12 +5366,12 @@ UPB_INLINE struct google_protobuf_SourceCodeInfo_Location* google_protobuf_Sourc /* google.protobuf.SourceCodeInfo.Location */ UPB_INLINE google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_Location_new(upb_Arena* arena) { - return (google_protobuf_SourceCodeInfo_Location*)_upb_Message_New(&google_protobuf_SourceCodeInfo_Location_msginit, arena); + return (google_protobuf_SourceCodeInfo_Location*)_upb_Message_New(&google_protobuf_SourceCodeInfo_Location_msg_init, arena); } UPB_INLINE google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_Location_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_SourceCodeInfo_Location* ret = google_protobuf_SourceCodeInfo_Location_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_Location_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_Location_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -4455,79 +5381,107 @@ UPB_INLINE google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeIn int options, upb_Arena* arena) { google_protobuf_SourceCodeInfo_Location* ret = google_protobuf_SourceCodeInfo_Location_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_Location_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_Location_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_SourceCodeInfo_Location_serialize(const google_protobuf_SourceCodeInfo_Location* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_SourceCodeInfo_Location_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_SourceCodeInfo_Location_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_SourceCodeInfo_Location_serialize_ex(const google_protobuf_SourceCodeInfo_Location* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_SourceCodeInfo_Location_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_SourceCodeInfo_Location_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_path(const google_protobuf_SourceCodeInfo_Location* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_path(const google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_span(const google_protobuf_SourceCodeInfo_Location* msg) { + _upb_array_detach(msg, UPB_SIZE(8, 16)); +} +UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_span(const google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(8, 16), len); +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); } -UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_path(const google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_span(const google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_leading_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE upb_StringView google_protobuf_SourceCodeInfo_Location_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_trailing_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return _upb_hasbit(msg, 2); } UPB_INLINE upb_StringView google_protobuf_SourceCodeInfo_Location_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + _upb_array_detach(msg, UPB_SIZE(28, 56)); +} +UPB_INLINE upb_StringView const* google_protobuf_SourceCodeInfo_Location_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); } -UPB_INLINE upb_StringView const* google_protobuf_SourceCodeInfo_Location_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); } -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_path(google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_path(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); } -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_path(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_Arena *arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, 2, arena); +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_path(google_protobuf_SourceCodeInfo_Location* msg, size_t len, upb_Arena* arena) { + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, 2, arena); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_path(google_protobuf_SourceCodeInfo_Location *msg, int32_t val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), 2, &val, - arena); +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_path(google_protobuf_SourceCodeInfo_Location* msg, int32_t val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), 2, &val, arena); } -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_span(google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_span(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 16), len); } -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_span(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_Arena *arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, 2, arena); +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_span(google_protobuf_SourceCodeInfo_Location* msg, size_t len, upb_Arena* arena) { + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(8, 16), len, 2, arena); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_span(google_protobuf_SourceCodeInfo_Location *msg, int32_t val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), 2, &val, - arena); +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_span(google_protobuf_SourceCodeInfo_Location* msg, int32_t val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(8, 16), 2, &val, arena); } UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_leading_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView value) { _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = value; } UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_trailing_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView) = value; } -UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_mutable_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { +UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_mutable_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); } -UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_resize_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_Arena *arena) { +UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_resize_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, size_t len, upb_Arena* arena) { return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(3, 4), arena); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(3, 4), &val, - arena); +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, upb_StringView val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(3, 4), &val, arena); } /* google.protobuf.GeneratedCodeInfo */ UPB_INLINE google_protobuf_GeneratedCodeInfo* google_protobuf_GeneratedCodeInfo_new(upb_Arena* arena) { - return (google_protobuf_GeneratedCodeInfo*)_upb_Message_New(&google_protobuf_GeneratedCodeInfo_msginit, arena); + return (google_protobuf_GeneratedCodeInfo*)_upb_Message_New(&google_protobuf_GeneratedCodeInfo_msg_init, arena); } UPB_INLINE google_protobuf_GeneratedCodeInfo* google_protobuf_GeneratedCodeInfo_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_GeneratedCodeInfo* ret = google_protobuf_GeneratedCodeInfo_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -4537,32 +5491,42 @@ UPB_INLINE google_protobuf_GeneratedCodeInfo* google_protobuf_GeneratedCodeInfo_ int options, upb_Arena* arena) { google_protobuf_GeneratedCodeInfo* ret = google_protobuf_GeneratedCodeInfo_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_GeneratedCodeInfo_serialize(const google_protobuf_GeneratedCodeInfo* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_GeneratedCodeInfo_serialize_ex(const google_protobuf_GeneratedCodeInfo* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_has_annotation(const google_protobuf_GeneratedCodeInfo* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_clear_annotation(const google_protobuf_GeneratedCodeInfo* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE const google_protobuf_GeneratedCodeInfo_Annotation* const* google_protobuf_GeneratedCodeInfo_annotation(const google_protobuf_GeneratedCodeInfo* msg, size_t* len) { + return (const google_protobuf_GeneratedCodeInfo_Annotation* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_has_annotation(const google_protobuf_GeneratedCodeInfo *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_GeneratedCodeInfo_Annotation* const* google_protobuf_GeneratedCodeInfo_annotation(const google_protobuf_GeneratedCodeInfo *msg, size_t *len) { return (const google_protobuf_GeneratedCodeInfo_Annotation* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_mutable_annotation(google_protobuf_GeneratedCodeInfo *msg, size_t *len) { +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_mutable_annotation(google_protobuf_GeneratedCodeInfo* msg, size_t* len) { return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_resize_annotation(google_protobuf_GeneratedCodeInfo *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_resize_annotation(google_protobuf_GeneratedCodeInfo* msg, size_t len, upb_Arena* arena) { return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_add_annotation(google_protobuf_GeneratedCodeInfo *msg, upb_Arena *arena) { - struct google_protobuf_GeneratedCodeInfo_Annotation* sub = (struct google_protobuf_GeneratedCodeInfo_Annotation*)_upb_Message_New(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); +UPB_INLINE struct google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_add_annotation(google_protobuf_GeneratedCodeInfo* msg, upb_Arena* arena) { + struct google_protobuf_GeneratedCodeInfo_Annotation* sub = (struct google_protobuf_GeneratedCodeInfo_Annotation*)_upb_Message_New(&google_protobuf_GeneratedCodeInfo_Annotation_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4570,12 +5534,12 @@ UPB_INLINE struct google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_ /* google.protobuf.GeneratedCodeInfo.Annotation */ UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_Annotation_new(upb_Arena* arena) { - return (google_protobuf_GeneratedCodeInfo_Annotation*)_upb_Message_New(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena); + return (google_protobuf_GeneratedCodeInfo_Annotation*)_upb_Message_New(&google_protobuf_GeneratedCodeInfo_Annotation_msg_init, arena); } UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_Annotation_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_GeneratedCodeInfo_Annotation* ret = google_protobuf_GeneratedCodeInfo_Annotation_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_Annotation_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -4585,46 +5549,82 @@ UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_Generat int options, upb_Arena* arena) { google_protobuf_GeneratedCodeInfo_Annotation* ret = google_protobuf_GeneratedCodeInfo_Annotation_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_Annotation_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_GeneratedCodeInfo_Annotation_serialize(const google_protobuf_GeneratedCodeInfo_Annotation* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_Annotation_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_GeneratedCodeInfo_Annotation_serialize_ex(const google_protobuf_GeneratedCodeInfo_Annotation* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_Annotation_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_path(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + _upb_array_detach(msg, UPB_SIZE(16, 16)); +} +UPB_INLINE int32_t const* google_protobuf_GeneratedCodeInfo_Annotation_path(const google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t* len) { + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(16, 16), len); +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); } -UPB_INLINE int32_t const* google_protobuf_GeneratedCodeInfo_Annotation_path(const google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(20, 32), len); } -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_source_file(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_hasbit(msg, 1); } UPB_INLINE upb_StringView google_protobuf_GeneratedCodeInfo_Annotation_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 16), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_StringView); +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 2); } -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_begin(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_hasbit(msg, 2); } UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_end(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 3); +} UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_semantic(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return _upb_hasbit(msg, 4); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_semantic(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = 0; + _upb_clearhas(msg, 4); +} +UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_semantic(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t); +} -UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_mutable_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t *len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 32), len); +UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_mutable_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t* len) { + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 16), len); } -UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_resize_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t len, upb_Arena *arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 32), len, 2, arena); +UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_resize_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t len, upb_Arena* arena) { + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 16), len, 2, arena); } -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_add_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 32), 2, &val, - arena); +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_add_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, int32_t val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(16, 16), 2, &val, arena); } UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_source_file(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_StringView value) { _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(12, 16), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_StringView) = value; } UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_begin(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { _upb_sethas(msg, 2); @@ -4634,6 +5634,10 @@ UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_end(google_prot _upb_sethas(msg, 3); *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; } +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_semantic(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { + _upb_sethas(msg, 4); + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = value; +} extern const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout; @@ -4648,794 +5652,1777 @@ extern const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout #endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ */ -/** upb/def.h ************************************************************/ -#ifndef UPB_DEF_H_ -#define UPB_DEF_H_ +#ifndef UPB_REFLECTION_DEF_H_ +#define UPB_REFLECTION_DEF_H_ -/* Must be last. */ +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ +#ifndef UPB_REFLECTION_DEF_POOL_H_ +#define UPB_REFLECTION_DEF_POOL_H_ + + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +// Declarations common to all public def types. + +#ifndef UPB_REFLECTION_COMMON_H_ +#define UPB_REFLECTION_COMMON_H_ + + +typedef enum { kUpb_Syntax_Proto2 = 2, kUpb_Syntax_Proto3 = 3 } upb_Syntax; -struct upb_EnumDef; +// Forward declarations for circular references. +typedef struct upb_DefPool upb_DefPool; typedef struct upb_EnumDef upb_EnumDef; -struct upb_EnumValueDef; typedef struct upb_EnumValueDef upb_EnumValueDef; -struct upb_ExtensionRange; typedef struct upb_ExtensionRange upb_ExtensionRange; -struct upb_FieldDef; typedef struct upb_FieldDef upb_FieldDef; -struct upb_FileDef; typedef struct upb_FileDef upb_FileDef; -struct upb_MethodDef; -typedef struct upb_MethodDef upb_MethodDef; -struct upb_MessageDef; typedef struct upb_MessageDef upb_MessageDef; -struct upb_OneofDef; +typedef struct upb_MethodDef upb_MethodDef; typedef struct upb_OneofDef upb_OneofDef; -struct upb_ServiceDef; typedef struct upb_ServiceDef upb_ServiceDef; -struct upb_streamdef; -typedef struct upb_streamdef upb_streamdef; -struct upb_DefPool; -typedef struct upb_DefPool upb_DefPool; -typedef enum { kUpb_Syntax_Proto2 = 2, kUpb_Syntax_Proto3 = 3 } upb_Syntax; +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// -/* All the different kind of well known type messages. For simplicity of check, - * number wrappers and string wrappers are grouped together. Make sure the - * order and merber of these groups are not changed. - */ -typedef enum { - kUpb_WellKnown_Unspecified, - kUpb_WellKnown_Any, - kUpb_WellKnown_FieldMask, - kUpb_WellKnown_Duration, - kUpb_WellKnown_Timestamp, - /* number wrappers */ - kUpb_WellKnown_DoubleValue, - kUpb_WellKnown_FloatValue, - kUpb_WellKnown_Int64Value, - kUpb_WellKnown_UInt64Value, - kUpb_WellKnown_Int32Value, - kUpb_WellKnown_UInt32Value, - /* string wrappers */ - kUpb_WellKnown_StringValue, - kUpb_WellKnown_BytesValue, - kUpb_WellKnown_BoolValue, - kUpb_WellKnown_Value, - kUpb_WellKnown_ListValue, - kUpb_WellKnown_Struct -} upb_WellKnown; +typedef struct upb_DefBuilder upb_DefBuilder; -/* upb_FieldDef ***************************************************************/ +#endif /* UPB_REFLECTION_COMMON_H_ */ -/* Maximum field number allowed for FieldDefs. This is an inherent limit of the - * protobuf wire format. */ -#define kUpb_MaxFieldNumber ((1 << 29) - 1) +#ifndef UPB_REFLECTION_DEF_TYPE_H_ +#define UPB_REFLECTION_DEF_TYPE_H_ -const google_protobuf_FieldOptions* upb_FieldDef_Options(const upb_FieldDef* f); -bool upb_FieldDef_HasOptions(const upb_FieldDef* f); -const char* upb_FieldDef_FullName(const upb_FieldDef* f); -upb_CType upb_FieldDef_CType(const upb_FieldDef* f); -upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f); -upb_Label upb_FieldDef_Label(const upb_FieldDef* f); -uint32_t upb_FieldDef_Number(const upb_FieldDef* f); -const char* upb_FieldDef_Name(const upb_FieldDef* f); -const char* upb_FieldDef_JsonName(const upb_FieldDef* f); -bool upb_FieldDef_HasJsonName(const upb_FieldDef* f); -bool upb_FieldDef_IsExtension(const upb_FieldDef* f); -bool upb_FieldDef_IsPacked(const upb_FieldDef* f); -const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f); -const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f); -const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f); -const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f); -const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f); -uint32_t upb_FieldDef_Index(const upb_FieldDef* f); -bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f); -bool upb_FieldDef_IsString(const upb_FieldDef* f); -bool upb_FieldDef_IsRepeated(const upb_FieldDef* f); -bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f); -bool upb_FieldDef_IsMap(const upb_FieldDef* f); -bool upb_FieldDef_HasDefault(const upb_FieldDef* f); -bool upb_FieldDef_HasSubDef(const upb_FieldDef* f); -bool upb_FieldDef_HasPresence(const upb_FieldDef* f); -const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f); -const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f); -const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f); -const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable( - const upb_FieldDef* f); -bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f); -/* upb_OneofDef ***************************************************************/ +// Must be last. -const google_protobuf_OneofOptions* upb_OneofDef_Options(const upb_OneofDef* o); -bool upb_OneofDef_HasOptions(const upb_OneofDef* o); -const char* upb_OneofDef_Name(const upb_OneofDef* o); -const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o); -uint32_t upb_OneofDef_Index(const upb_OneofDef* o); -bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o); -int upb_OneofDef_FieldCount(const upb_OneofDef* o); -const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i); +// Inside a symtab we store tagged pointers to specific def types. +typedef enum { + UPB_DEFTYPE_MASK = 7, -/* Oneof lookups: - * - ntof: look up a field by name. - * - ntofz: look up a field by name (as a null-terminated string). - * - itof: look up a field by number. */ -const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, - const char* name, - size_t length); -UPB_INLINE const upb_FieldDef* upb_OneofDef_LookupName(const upb_OneofDef* o, - const char* name) { - return upb_OneofDef_LookupNameWithSize(o, name, strlen(name)); -} -const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, - uint32_t num); + // Only inside symtab table. + UPB_DEFTYPE_EXT = 0, + UPB_DEFTYPE_MSG = 1, + UPB_DEFTYPE_ENUM = 2, + UPB_DEFTYPE_ENUMVAL = 3, + UPB_DEFTYPE_SERVICE = 4, -/* upb_MessageDef *************************************************************/ + // Only inside message table. + UPB_DEFTYPE_FIELD = 0, + UPB_DEFTYPE_ONEOF = 1, + UPB_DEFTYPE_FIELD_JSONNAME = 2, +} upb_deftype_t; -/* Well-known field tag numbers for map-entry messages. */ -#define kUpb_MapEntry_KeyFieldNumber 1 -#define kUpb_MapEntry_ValueFieldNumber 2 +#ifdef __cplusplus +extern "C" { +#endif -/* Well-known field tag numbers for Any messages. */ -#define kUpb_Any_TypeFieldNumber 1 -#define kUpb_Any_ValueFieldNumber 2 +// Our 3-bit pointer tagging requires all pointers to be multiples of 8. +// The arena will always yield 8-byte-aligned addresses, however we put +// the defs into arrays. For each element in the array to be 8-byte-aligned, +// the sizes of each def type must also be a multiple of 8. +// +// If any of these asserts fail, we need to add or remove padding on 32-bit +// machines (64-bit machines will have 8-byte alignment already due to +// pointers, which all of these structs have). +UPB_INLINE void _upb_DefType_CheckPadding(size_t size) { + UPB_ASSERT((size & UPB_DEFTYPE_MASK) == 0); +} -/* Well-known field tag numbers for timestamp messages. */ -#define kUpb_Duration_SecondsFieldNumber 1 -#define kUpb_Duration_NanosFieldNumber 2 +upb_deftype_t _upb_DefType_Type(upb_value v); -/* Well-known field tag numbers for duration messages. */ -#define kUpb_Timestamp_SecondsFieldNumber 1 -#define kUpb_Timestamp_NanosFieldNumber 2 +upb_value _upb_DefType_Pack(const void* ptr, upb_deftype_t type); -const google_protobuf_MessageOptions* upb_MessageDef_Options( - const upb_MessageDef* m); -bool upb_MessageDef_HasOptions(const upb_MessageDef* m); -const char* upb_MessageDef_FullName(const upb_MessageDef* m); -const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m); -const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m); -const char* upb_MessageDef_Name(const upb_MessageDef* m); -upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m); -upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m); -int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m); -int upb_MessageDef_FieldCount(const upb_MessageDef* m); -int upb_MessageDef_OneofCount(const upb_MessageDef* m); -const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, - int i); -const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i); -const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i); -const upb_FieldDef* upb_MessageDef_FindFieldByNumber(const upb_MessageDef* m, - uint32_t i); -const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( - const upb_MessageDef* m, const char* name, size_t len); -const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( - const upb_MessageDef* m, const char* name, size_t len); -const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m); +const void* _upb_DefType_Unpack(upb_value v, upb_deftype_t type); -UPB_INLINE const upb_OneofDef* upb_MessageDef_FindOneofByName( - const upb_MessageDef* m, const char* name) { - return upb_MessageDef_FindOneofByNameWithSize(m, name, strlen(name)); -} +#ifdef __cplusplus +} /* extern "C" */ +#endif -UPB_INLINE const upb_FieldDef* upb_MessageDef_FindFieldByName( - const upb_MessageDef* m, const char* name) { - return upb_MessageDef_FindFieldByNameWithSize(m, name, strlen(name)); -} -UPB_INLINE bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m) { - return google_protobuf_MessageOptions_map_entry(upb_MessageDef_Options(m)); -} +#endif /* UPB_REFLECTION_DEF_TYPE_H_ */ -/* Nested entities. */ -int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m); -int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m); -int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m); -const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, - int i); -const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i); -const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, - int i); +// Must be last. -/* Lookup of either field or oneof by name. Returns whether either was found. - * If the return is true, then the found def will be set, and the non-found - * one set to NULL. */ -bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, - const char* name, size_t len, - const upb_FieldDef** f, - const upb_OneofDef** o); +#ifdef __cplusplus +extern "C" { +#endif -UPB_INLINE bool upb_MessageDef_FindByName(const upb_MessageDef* m, - const char* name, - const upb_FieldDef** f, - const upb_OneofDef** o) { - return upb_MessageDef_FindByNameWithSize(m, name, strlen(name), f, o); -} +void upb_DefPool_Free(upb_DefPool* s); -/* Returns a field by either JSON name or regular proto name. */ -const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( - const upb_MessageDef* m, const char* name, size_t len); -UPB_INLINE const upb_FieldDef* upb_MessageDef_FindByJsonName( - const upb_MessageDef* m, const char* name) { - return upb_MessageDef_FindByJsonNameWithSize(m, name, strlen(name)); -} +upb_DefPool* upb_DefPool_New(void); -/* upb_ExtensionRange *********************************************************/ +const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, + const char* sym); -const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( - const upb_ExtensionRange* r); -bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r); -int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* r); -int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r); +const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( + const upb_DefPool* s, const char* sym, size_t len); -/* upb_EnumDef ****************************************************************/ +const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, + const char* sym); -const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e); -bool upb_EnumDef_HasOptions(const upb_EnumDef* e); -const char* upb_EnumDef_FullName(const upb_EnumDef* e); -const char* upb_EnumDef_Name(const upb_EnumDef* e); -const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e); -const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e); -int32_t upb_EnumDef_Default(const upb_EnumDef* e); -int upb_EnumDef_ValueCount(const upb_EnumDef* e); -const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i); +const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, + const char* sym); + +const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, + const char* name); + +const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, + const char* name, + size_t len); + +const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( + const upb_DefPool* s, const char* name, size_t size); + +const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, + const char* sym); + +const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, + const char* name); + +const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( + const upb_DefPool* s, const char* name, size_t size); + +const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, + const char* name); + +const upb_FileDef* upb_DefPool_AddFile( + upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, + upb_Status* status); + +const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, + const upb_MessageDef* m, + int32_t fieldnum); + +const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( + const upb_DefPool* s); + +const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, + const upb_MessageDef* m, + size_t* count); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s); +size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s); +upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s); +const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable( + const upb_DefPool* s, const upb_MiniTable_Extension* ext); + +bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTable_Extension* ext, + upb_FieldDef* f); +bool _upb_DefPool_InsertSym(upb_DefPool* s, upb_StringView sym, upb_value v, + upb_Status* status); +bool _upb_DefPool_LookupSym(const upb_DefPool* s, const char* sym, size_t size, + upb_value* v); + +void** _upb_DefPool_ScratchData(const upb_DefPool* s); +size_t* _upb_DefPool_ScratchSize(const upb_DefPool* s); + +// For generated code only: loads a generated descriptor. +typedef struct _upb_DefPool_Init { + struct _upb_DefPool_Init** deps; // Dependencies of this file. + const upb_MiniTable_File* layout; + const char* filename; + upb_StringView descriptor; // Serialized descriptor. +} _upb_DefPool_Init; + +bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init); + +// Should only be directly called by tests. This variant lets us suppress +// the use of compiled-in tables, forcing a rebuild of the tables at runtime. +bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, + bool rebuild_minitable); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_DEF_POOL_H_ */ +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_ENUM_DEF_H_ +#define UPB_REFLECTION_ENUM_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num); +const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e); +int32_t upb_EnumDef_Default(const upb_EnumDef* e); +const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e); +const upb_EnumValueDef* upb_EnumDef_FindValueByName(const upb_EnumDef* e, + const char* name); const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( - const upb_EnumDef* e, const char* name, size_t len); + const upb_EnumDef* e, const char* name, size_t size); const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* e, int32_t num); -bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num); +const char* upb_EnumDef_FullName(const upb_EnumDef* e); +bool upb_EnumDef_HasOptions(const upb_EnumDef* e); -// Convenience wrapper. -UPB_INLINE const upb_EnumValueDef* upb_EnumDef_FindValueByName( - const upb_EnumDef* e, const char* name) { - return upb_EnumDef_FindValueByNameWithSize(e, name, strlen(name)); -} +// Creates a mini descriptor string for an enum, returns true on success. +bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, + upb_StringView* out); + +const char* upb_EnumDef_Name(const upb_EnumDef* e); +const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e); +const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i); +int upb_EnumDef_ValueCount(const upb_EnumDef* e); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i); +bool _upb_EnumDef_Insert(upb_EnumDef* e, upb_EnumValueDef* v, upb_Arena* a); +const upb_MiniTable_Enum* _upb_EnumDef_MiniTable(const upb_EnumDef* e); + +// Allocate and initialize an array of |n| enum defs. +upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, + const google_protobuf_EnumDescriptorProto* const* protos, + const upb_MessageDef* containing_type); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ENUM_DEF_H_ */ -/* upb_EnumValueDef ***********************************************************/ +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +#ifndef UPB_REFLECTION_ENUM_VALUE_DEF_H_ +#define UPB_REFLECTION_ENUM_VALUE_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* v); +const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* v); +bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* v); +uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v); +const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v); +int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v); const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( - const upb_EnumValueDef* e); -bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* e); -const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* e); -const char* upb_EnumValueDef_Name(const upb_EnumValueDef* e); -int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* e); -uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* e); -const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* e); + const upb_EnumValueDef* v); -/* upb_FileDef ****************************************************************/ +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// -const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f); +upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i); + +// Allocate and initialize an array of |n| enum value defs owned by |e|. +upb_EnumValueDef* _upb_EnumValueDefs_New( + upb_DefBuilder* ctx, const char* prefix, int n, + const google_protobuf_EnumValueDescriptorProto* const* protos, upb_EnumDef* e, + bool* is_sorted); + +const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v, + int n, upb_Arena* a); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ENUM_VALUE_DEF_H_ */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_EXTENSION_RANGE_H_ +#define UPB_REFLECTION_EXTENSION_RANGE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* r); +int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r); + +bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r); +const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( + const upb_ExtensionRange* r); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_ExtensionRange* _upb_ExtensionRange_At(const upb_ExtensionRange* r, int i); + +// Allocate and initialize an array of |n| extension ranges owned by |m|. +upb_ExtensionRange* _upb_ExtensionRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_DescriptorProto_ExtensionRange* const* protos, + const upb_MessageDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_EXTENSION_RANGE_H_ */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_FIELD_DEF_H_ +#define UPB_REFLECTION_FIELD_DEF_H_ + + +// Must be last. + +// Maximum field number allowed for FieldDefs. +// This is an inherent limit of the protobuf wire format. +#define kUpb_MaxFieldNumber ((1 << 29) - 1) + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f); +const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f); +upb_CType upb_FieldDef_CType(const upb_FieldDef* f); +const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f); +const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f); +const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f); +const char* upb_FieldDef_FullName(const upb_FieldDef* f); +bool upb_FieldDef_HasDefault(const upb_FieldDef* f); +bool upb_FieldDef_HasJsonName(const upb_FieldDef* f); +bool upb_FieldDef_HasOptions(const upb_FieldDef* f); +bool upb_FieldDef_HasPresence(const upb_FieldDef* f); +bool upb_FieldDef_HasSubDef(const upb_FieldDef* f); +uint32_t upb_FieldDef_Index(const upb_FieldDef* f); +bool upb_FieldDef_IsExtension(const upb_FieldDef* f); +bool upb_FieldDef_IsMap(const upb_FieldDef* f); +bool upb_FieldDef_IsOptional(const upb_FieldDef* f); +bool upb_FieldDef_IsPacked(const upb_FieldDef* f); +bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f); +bool upb_FieldDef_IsRepeated(const upb_FieldDef* f); +bool upb_FieldDef_IsRequired(const upb_FieldDef* f); +bool upb_FieldDef_IsString(const upb_FieldDef* f); +bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f); +const char* upb_FieldDef_JsonName(const upb_FieldDef* f); +upb_Label upb_FieldDef_Label(const upb_FieldDef* f); +const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f); + +// Creates a mini descriptor string for a field, returns true on success. +bool upb_FieldDef_MiniDescriptorEncode(const upb_FieldDef* f, upb_Arena* a, + upb_StringView* out); + +const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f); +const char* upb_FieldDef_Name(const upb_FieldDef* f); +uint32_t upb_FieldDef_Number(const upb_FieldDef* f); +const google_protobuf_FieldOptions* upb_FieldDef_Options(const upb_FieldDef* f); +const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f); +upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i); + +const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable( + const upb_FieldDef* f); +bool _upb_FieldDef_IsClosedEnum(const upb_FieldDef* f); +bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f); +int _upb_FieldDef_LayoutIndex(const upb_FieldDef* f); +uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f); +void _upb_FieldDef_Resolve(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f); + +// Allocate and initialize an array of |n| field defs. +upb_FieldDef* _upb_FieldDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_FieldDescriptorProto* const* protos, const char* prefix, + upb_MessageDef* m, bool* is_sorted); + +// Allocate and return a list of pointers to the |n| field defs in |ff|, +// sorted by field number. +const upb_FieldDef** _upb_FieldDefs_Sorted(const upb_FieldDef* f, int n, + upb_Arena* a); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_FIELD_DEF_H_ */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_FILE_DEF_H_ +#define UPB_REFLECTION_FILE_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i); +int upb_FileDef_DependencyCount(const upb_FileDef* f); bool upb_FileDef_HasOptions(const upb_FileDef* f); const char* upb_FileDef_Name(const upb_FileDef* f); +const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f); const char* upb_FileDef_Package(const upb_FileDef* f); -upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f); -int upb_FileDef_DependencyCount(const upb_FileDef* f); +const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f); + +const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i); int upb_FileDef_PublicDependencyCount(const upb_FileDef* f); -int upb_FileDef_WeakDependencyCount(const upb_FileDef* f); -int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f); -int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f); -int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f); + +const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i); int upb_FileDef_ServiceCount(const upb_FileDef* f); -const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i); -const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i); -const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i); -const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i); + +upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f); + const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i); +int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f); + const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i); -const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i); -const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f); -const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f); -const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f); +int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f); -/* upb_MethodDef **************************************************************/ +const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i); +int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f); -const google_protobuf_MethodOptions* upb_MethodDef_Options( - const upb_MethodDef* m); -bool upb_MethodDef_HasOptions(const upb_MethodDef* m); -const char* upb_MethodDef_FullName(const upb_MethodDef* m); -int upb_MethodDef_Index(const upb_MethodDef* m); -const char* upb_MethodDef_Name(const upb_MethodDef* m); -const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m); -const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m); -const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m); -bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m); -bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m); +const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i); +int upb_FileDef_WeakDependencyCount(const upb_FileDef* f); -/* upb_ServiceDef *************************************************************/ +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// -const google_protobuf_ServiceOptions* upb_ServiceDef_Options( - const upb_ServiceDef* s); -bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s); -const char* upb_ServiceDef_FullName(const upb_ServiceDef* s); -const char* upb_ServiceDef_Name(const upb_ServiceDef* s); -int upb_ServiceDef_Index(const upb_ServiceDef* s); -const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s); -int upb_ServiceDef_MethodCount(const upb_ServiceDef* s); -const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i); -const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, - const char* name); +const upb_MiniTable_Extension* _upb_FileDef_ExtensionMiniTable( + const upb_FileDef* f, int i); +const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f); +const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f); -/* upb_DefPool ****************************************************************/ +// upb_FileDef_Package() returns "" if f->package is NULL, this does not. +const char* _upb_FileDef_RawPackage(const upb_FileDef* f); -upb_DefPool* upb_DefPool_New(void); -void upb_DefPool_Free(upb_DefPool* s); -const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, - const char* sym); -const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( - const upb_DefPool* s, const char* sym, size_t len); -const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, - const char* sym); -const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, - const char* sym); -const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, - const char* sym); -const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( - const upb_DefPool* s, const char* sym, size_t len); -const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, - const char* name); -const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, - const char* name); -const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( - const upb_DefPool* s, const char* name, size_t size); -const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, - const char* name); -const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, - const char* name, - size_t len); -const upb_FileDef* upb_DefPool_AddFile( - upb_DefPool* s, const google_protobuf_FileDescriptorProto* file, - upb_Status* status); -size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s); -upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s); -const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable( - const upb_DefPool* s, const upb_MiniTable_Extension* ext); -const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, - const upb_MessageDef* m, - int32_t fieldnum); -const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( - const upb_DefPool* s); -const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, - const upb_MessageDef* m, - size_t* count); +void _upb_FileDef_Create(upb_DefBuilder* ctx, + const google_protobuf_FileDescriptorProto* file_proto); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_FILE_DEF_H_ */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_MESSAGE_DEF_H_ +#define UPB_REFLECTION_MESSAGE_DEF_H_ + + +// Must be last. + +// Well-known field tag numbers for map-entry messages. +#define kUpb_MapEntry_KeyFieldNumber 1 +#define kUpb_MapEntry_ValueFieldNumber 2 + +// Well-known field tag numbers for Any messages. +#define kUpb_Any_TypeFieldNumber 1 +#define kUpb_Any_ValueFieldNumber 2 + +// Well-known field tag numbers for duration messages. +#define kUpb_Duration_SecondsFieldNumber 1 +#define kUpb_Duration_NanosFieldNumber 2 + +// Well-known field tag numbers for timestamp messages. +#define kUpb_Timestamp_SecondsFieldNumber 1 +#define kUpb_Timestamp_NanosFieldNumber 2 + +// All the different kind of well known type messages. For simplicity of check, +// number wrappers and string wrappers are grouped together. Make sure the +// order and number of these groups are not changed. +typedef enum { + kUpb_WellKnown_Unspecified, + kUpb_WellKnown_Any, + kUpb_WellKnown_FieldMask, + kUpb_WellKnown_Duration, + kUpb_WellKnown_Timestamp, + + // number wrappers + kUpb_WellKnown_DoubleValue, + kUpb_WellKnown_FloatValue, + kUpb_WellKnown_Int64Value, + kUpb_WellKnown_UInt64Value, + kUpb_WellKnown_Int32Value, + kUpb_WellKnown_UInt32Value, + + // string wrappers + kUpb_WellKnown_StringValue, + kUpb_WellKnown_BytesValue, + kUpb_WellKnown_BoolValue, + kUpb_WellKnown_Value, + kUpb_WellKnown_ListValue, + kUpb_WellKnown_Struct, +} upb_WellKnown; + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m); + +const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, + int i); +int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m); + +const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i); +int upb_MessageDef_FieldCount(const upb_MessageDef* m); + +const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m); + +// Returns a field by either JSON name or regular proto name. +const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( + const upb_MessageDef* m, const char* name, size_t size); +UPB_INLINE const upb_FieldDef* upb_MessageDef_FindByJsonName( + const upb_MessageDef* m, const char* name) { + return upb_MessageDef_FindByJsonNameWithSize(m, name, strlen(name)); +} + +// Lookup of either field or oneof by name. Returns whether either was found. +// If the return is true, then the found def will be set, and the non-found +// one set to NULL. +bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, + const char* name, size_t size, + const upb_FieldDef** f, + const upb_OneofDef** o); +UPB_INLINE bool upb_MessageDef_FindByName(const upb_MessageDef* m, + const char* name, + const upb_FieldDef** f, + const upb_OneofDef** o) { + return upb_MessageDef_FindByNameWithSize(m, name, strlen(name), f, o); +} + +const upb_FieldDef* upb_MessageDef_FindFieldByName(const upb_MessageDef* m, + const char* name); +const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size); +const upb_FieldDef* upb_MessageDef_FindFieldByNumber(const upb_MessageDef* m, + uint32_t i); +const upb_OneofDef* upb_MessageDef_FindOneofByName(const upb_MessageDef* m, + const char* name); +const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size); +const char* upb_MessageDef_FullName(const upb_MessageDef* m); +bool upb_MessageDef_HasOptions(const upb_MessageDef* m); +bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m); +bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m); + +// Creates a mini descriptor string for a message, returns true on success. +bool upb_MessageDef_MiniDescriptorEncode(const upb_MessageDef* m, upb_Arena* a, + upb_StringView* out); + +const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m); +const char* upb_MessageDef_Name(const upb_MessageDef* m); + +const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i); +const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, + int i); +const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, + int i); + +int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m); +int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m); +int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m); + +const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i); +int upb_MessageDef_OneofCount(const upb_MessageDef* m); + +const google_protobuf_MessageOptions* upb_MessageDef_Options(const upb_MessageDef* m); +upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m); +upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_MessageDef* _upb_MessageDef_At(const upb_MessageDef* m, int i); +bool _upb_MessageDef_InMessageSet(const upb_MessageDef* m); +bool _upb_MessageDef_Insert(upb_MessageDef* m, const char* name, size_t size, + upb_value v, upb_Arena* a); +void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m, + const upb_FieldDef* f); +bool _upb_MessageDef_IsValidExtensionNumber(const upb_MessageDef* m, int n); +void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx, + const upb_MessageDef* m); +void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m); + +// Allocate and initialize an array of |n| message defs. +upb_MessageDef* _upb_MessageDefs_New( + upb_DefBuilder* ctx, int n, const google_protobuf_DescriptorProto* const* protos, + const upb_MessageDef* containing_type); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_MESSAGE_DEF_H_ */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_METHOD_DEF_H_ +#define UPB_REFLECTION_METHOD_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m); +const char* upb_MethodDef_FullName(const upb_MethodDef* m); +bool upb_MethodDef_HasOptions(const upb_MethodDef* m); +int upb_MethodDef_Index(const upb_MethodDef* m); +const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m); +const char* upb_MethodDef_Name(const upb_MethodDef* m); +const google_protobuf_MethodOptions* upb_MethodDef_Options(const upb_MethodDef* m); +const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m); +bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m); +const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_MethodDef* _upb_MethodDef_At(const upb_MethodDef* m, int i); + +// Allocate and initialize an array of |n| method defs owned by |s|. +upb_MethodDef* _upb_MethodDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_MethodDescriptorProto* const* protos, upb_ServiceDef* s); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_METHOD_DEF_H_ */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_ONEOF_DEF_H_ +#define UPB_REFLECTION_ONEOF_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o); +const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i); +int upb_OneofDef_FieldCount(const upb_OneofDef* o); +const char* upb_OneofDef_FullName(const upb_OneofDef* o); +bool upb_OneofDef_HasOptions(const upb_OneofDef* o); +uint32_t upb_OneofDef_Index(const upb_OneofDef* o); +bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o); +const upb_FieldDef* upb_OneofDef_LookupName(const upb_OneofDef* o, + const char* name); +const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, + const char* name, + size_t size); +const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, + uint32_t num); +const char* upb_OneofDef_Name(const upb_OneofDef* o); +int upb_OneofDef_numfields(const upb_OneofDef* o); +const google_protobuf_OneofOptions* upb_OneofDef_Options(const upb_OneofDef* o); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_OneofDef* _upb_OneofDef_At(const upb_OneofDef* o, int i); +bool _upb_OneofDef_Insert(upb_OneofDef* o, const upb_FieldDef* f, + const char* name, size_t size, upb_Arena* a); + +// Allocate and initialize an array of |n| oneof defs owned by |m|. +upb_OneofDef* _upb_OneofDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_OneofDescriptorProto* const* protos, upb_MessageDef* m); + +size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ONEOF_DEF_H_ */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_SERVICE_DEF_H_ +#define UPB_REFLECTION_SERVICE_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s); +const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, + const char* name); +const char* upb_ServiceDef_FullName(const upb_ServiceDef* s); +bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s); +int upb_ServiceDef_Index(const upb_ServiceDef* s); +const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i); +int upb_ServiceDef_MethodCount(const upb_ServiceDef* s); +const char* upb_ServiceDef_Name(const upb_ServiceDef* s); +const google_protobuf_ServiceOptions* upb_ServiceDef_Options(const upb_ServiceDef* s); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int i); + +// Allocate and initialize an array of |n| service defs. +upb_ServiceDef* _upb_ServiceDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_ServiceDescriptorProto* const* protos); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_SERVICE_DEF_H_ */ + +#endif /* UPB_REFLECTION_DEF_H_ */ +/* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/descriptor.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ + +#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPBDEFS_H_ +#define GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPBDEFS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + + +extern _upb_DefPool_Init google_protobuf_descriptor_proto_upbdefinit; + +UPB_INLINE const upb_MessageDef *google_protobuf_FileDescriptorSet_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.FileDescriptorSet"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_FileDescriptorProto_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.FileDescriptorProto"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_DescriptorProto_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.DescriptorProto"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_DescriptorProto_ExtensionRange_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.DescriptorProto.ExtensionRange"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_DescriptorProto_ReservedRange_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.DescriptorProto.ReservedRange"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_ExtensionRangeOptions_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.ExtensionRangeOptions"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_FieldDescriptorProto_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.FieldDescriptorProto"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_OneofDescriptorProto_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.OneofDescriptorProto"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_EnumDescriptorProto_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.EnumDescriptorProto"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_EnumDescriptorProto_EnumReservedRange_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.EnumDescriptorProto.EnumReservedRange"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_EnumValueDescriptorProto_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.EnumValueDescriptorProto"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_ServiceDescriptorProto_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.ServiceDescriptorProto"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_MethodDescriptorProto_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.MethodDescriptorProto"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_FileOptions_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.FileOptions"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_MessageOptions_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.MessageOptions"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_FieldOptions_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.FieldOptions"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_OneofOptions_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.OneofOptions"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_EnumOptions_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.EnumOptions"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_EnumValueOptions_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.EnumValueOptions"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_ServiceOptions_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.ServiceOptions"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_MethodOptions_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.MethodOptions"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_UninterpretedOption_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.UninterpretedOption"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_UninterpretedOption_NamePart_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.UninterpretedOption.NamePart"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_SourceCodeInfo_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.SourceCodeInfo"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_SourceCodeInfo_Location_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.SourceCodeInfo.Location"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_GeneratedCodeInfo_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.GeneratedCodeInfo"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_GeneratedCodeInfo_Annotation_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.GeneratedCodeInfo.Annotation"); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPBDEFS_H_ */ + +/* + * Internal implementation details of the decoder that are shared between + * decode.c and decode_fast.c. + */ + +#ifndef UPB_INTERNAL_DECODE_H_ +#define UPB_INTERNAL_DECODE_H_ + + +#ifndef UPB_INTERNAL_ARENA_H_ +#define UPB_INTERNAL_ARENA_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct mem_block mem_block; + +struct upb_Arena { + _upb_ArenaHead head; + /* Stores cleanup metadata for this arena. + * - a pointer to the current cleanup counter. + * - a boolean indicating if there is an unowned initial block. */ + uintptr_t cleanup_metadata; + + /* Allocator to allocate arena blocks. We are responsible for freeing these + * when we are destroyed. */ + upb_alloc* block_alloc; + uint32_t last_size; + + /* When multiple arenas are fused together, each arena points to a parent + * arena (root points to itself). The root tracks how many live arenas + * reference it. */ + uint32_t refcount; /* Only used when a->parent == a */ + struct upb_Arena* parent; + + /* Linked list of blocks to free/cleanup. */ + mem_block *freelist, *freelist_tail; +}; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_INTERNAL_ARENA_H_ */ + +#include "third_party/utf8_range/utf8_range.h" + +// Must be last. + +#define DECODE_NOGROUP (uint32_t) - 1 + +typedef struct upb_Decoder { + const char* end; /* Can read up to 16 bytes slop beyond this. */ + const char* limit_ptr; /* = end + UPB_MIN(limit, 0) */ + upb_Message* unknown_msg; /* Used for preserving unknown data. */ + const char* unknown; /* Start of unknown data, preserve at buffer flip. */ + const upb_ExtensionRegistry* + extreg; /* For looking up extensions during the parse. */ + int limit; /* Submessage limit relative to end. */ + int depth; /* Tracks recursion depth to bound stack usage. */ + uint32_t end_group; /* field number of END_GROUP tag, else DECODE_NOGROUP */ + uint16_t options; + bool missing_required; + char patch[32]; + upb_Arena arena; + jmp_buf err; + +#ifndef NDEBUG + const char* debug_tagstart; + const char* debug_valstart; +#endif +} upb_Decoder; + +/* Error function that will abort decoding with longjmp(). We can't declare this + * UPB_NORETURN, even though it is appropriate, because if we do then compilers + * will "helpfully" refuse to tailcall to it + * (see: https://stackoverflow.com/a/55657013), which will defeat a major goal + * of our optimizations. That is also why we must declare it in a separate file, + * otherwise the compiler will see that it calls longjmp() and deduce that it is + * noreturn. */ +const char* _upb_FastDecoder_ErrorJmp(upb_Decoder* d, int status); + +extern const uint8_t upb_utf8_offsets[]; + +UPB_INLINE +bool _upb_Decoder_VerifyUtf8Inline(const char* ptr, int len) { + const char* end = ptr + len; + + // Check 8 bytes at a time for any non-ASCII char. + while (end - ptr >= 8) { + uint64_t data; + memcpy(&data, ptr, 8); + if (data & 0x8080808080808080) goto non_ascii; + ptr += 8; + } + + // Check one byte at a time for non-ASCII. + while (ptr < end) { + if (*ptr & 0x80) goto non_ascii; + ptr++; + } + + return true; + +non_ascii: + return utf8_range2((const unsigned char*)ptr, end - ptr) == 0; +} + +const char* _upb_Decoder_CheckRequired(upb_Decoder* d, const char* ptr, + const upb_Message* msg, + const upb_MiniTable* l); + +/* x86-64 pointers always have the high 16 bits matching. So we can shift + * left 8 and right 8 without loss of information. */ +UPB_INLINE intptr_t decode_totable(const upb_MiniTable* tablep) { + return ((intptr_t)tablep << 8) | tablep->table_mask; +} + +UPB_INLINE const upb_MiniTable* decode_totablep(intptr_t table) { + return (const upb_MiniTable*)(table >> 8); +} + +UPB_INLINE +const char* _upb_Decoder_IsDoneFallbackInline(upb_Decoder* d, const char* ptr, + int overrun, int* status) { + if (overrun < d->limit) { + /* Need to copy remaining data into patch buffer. */ + UPB_ASSERT(overrun < 16); + if (d->unknown) { + if (!_upb_Message_AddUnknown(d->unknown_msg, d->unknown, ptr - d->unknown, + &d->arena)) { + *status = kUpb_DecodeStatus_OutOfMemory; + return NULL; + } + d->unknown = &d->patch[0] + overrun; + } + memset(d->patch + 16, 0, 16); + memcpy(d->patch, d->end, 16); + ptr = &d->patch[0] + overrun; + d->end = &d->patch[16]; + d->limit -= 16; + d->limit_ptr = d->end + d->limit; + d->options &= ~kUpb_DecodeOption_AliasString; + UPB_ASSERT(ptr < d->limit_ptr); + return ptr; + } else { + *status = kUpb_DecodeStatus_Malformed; + return NULL; + } +} + +const char* _upb_Decoder_IsDoneFallback(upb_Decoder* d, const char* ptr, + int overrun); + +UPB_INLINE +bool _upb_Decoder_IsDone(upb_Decoder* d, const char** ptr) { + int overrun = *ptr - d->end; + if (UPB_LIKELY(*ptr < d->limit_ptr)) { + return false; + } else if (UPB_LIKELY(overrun == d->limit)) { + return true; + } else { + *ptr = _upb_Decoder_IsDoneFallback(d, *ptr, overrun); + return false; + } +} + +#if UPB_FASTTABLE +UPB_INLINE +const char* _upb_FastDecoder_TagDispatch(upb_Decoder* d, const char* ptr, + upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t tag) { + const upb_MiniTable* table_p = decode_totablep(table); + uint8_t mask = table; + uint64_t data; + size_t idx = tag & mask; + UPB_ASSUME((idx & 7) == 0); + idx >>= 3; + data = table_p->fasttable[idx].field_data ^ tag; + UPB_MUSTTAIL return table_p->fasttable[idx].field_parser(d, ptr, msg, table, + hasbits, data); +} +#endif + +UPB_INLINE uint32_t _upb_FastDecoder_LoadTag(const char* ptr) { + uint16_t tag; + memcpy(&tag, ptr, 2); + return tag; +} -/* For generated code only: loads a generated descriptor. */ -typedef struct _upb_DefPool_Init { - struct _upb_DefPool_Init** deps; /* Dependencies of this file. */ - const upb_MiniTable_File* layout; - const char* filename; - upb_StringView descriptor; /* Serialized descriptor. */ -} _upb_DefPool_Init; +UPB_INLINE void _upb_Decoder_CheckLimit(upb_Decoder* d) { + UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); +} -// Should only be directly called by tests. This variant lets us suppress -// the use of compiled-in tables, forcing a rebuild of the tables at runtime. -bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, - bool rebuild_minitable); +UPB_INLINE int _upb_Decoder_PushLimit(upb_Decoder* d, const char* ptr, + int size) { + int limit = size + (int)(ptr - d->end); + int delta = d->limit - limit; + _upb_Decoder_CheckLimit(d); + d->limit = limit; + d->limit_ptr = d->end + UPB_MIN(0, limit); + _upb_Decoder_CheckLimit(d); + return delta; +} -UPB_INLINE bool _upb_DefPool_LoadDefInit(upb_DefPool* s, - const _upb_DefPool_Init* init) { - return _upb_DefPool_LoadDefInitEx(s, init, false); +UPB_INLINE void _upb_Decoder_PopLimit(upb_Decoder* d, const char* ptr, + int saved_delta) { + UPB_ASSERT(ptr - d->end == d->limit); + _upb_Decoder_CheckLimit(d); + d->limit += saved_delta; + d->limit_ptr = d->end + UPB_MIN(0, d->limit); + _upb_Decoder_CheckLimit(d); } -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ +#endif /* UPB_INTERNAL_DECODE_H_ */ -#endif /* UPB_DEF_H_ */ +#ifndef UPB_JSON_DECODE_H_ +#define UPB_JSON_DECODE_H_ -/** google/protobuf/descriptor.upbdefs.h ************************************************************//* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/descriptor.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ -#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPBDEFS_H_ -#define GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPBDEFS_H_ +// Must be last. #ifdef __cplusplus extern "C" { #endif +enum { upb_JsonDecode_IgnoreUnknown = 1 }; +bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, + const upb_MessageDef* m, const upb_DefPool* symtab, + int options, upb_Arena* arena, upb_Status* status); -extern _upb_DefPool_Init google_protobuf_descriptor_proto_upbdefinit; +#ifdef __cplusplus +} /* extern "C" */ +#endif -UPB_INLINE const upb_MessageDef *google_protobuf_FileDescriptorSet_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.FileDescriptorSet"); -} -UPB_INLINE const upb_MessageDef *google_protobuf_FileDescriptorProto_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.FileDescriptorProto"); -} +#endif /* UPB_JSONDECODE_H_ */ -UPB_INLINE const upb_MessageDef *google_protobuf_DescriptorProto_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.DescriptorProto"); -} +#ifndef UPB_INTERNAL_UNICODE_H_ +#define UPB_INTERNAL_UNICODE_H_ -UPB_INLINE const upb_MessageDef *google_protobuf_DescriptorProto_ExtensionRange_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.DescriptorProto.ExtensionRange"); -} +// Must be last. -UPB_INLINE const upb_MessageDef *google_protobuf_DescriptorProto_ReservedRange_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.DescriptorProto.ReservedRange"); -} +#ifdef __cplusplus +extern "C" { +#endif -UPB_INLINE const upb_MessageDef *google_protobuf_ExtensionRangeOptions_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.ExtensionRangeOptions"); +// Returns true iff a codepoint is the value for a high surrogate. +UPB_INLINE bool upb_Unicode_IsHigh(uint32_t cp) { + return (cp >= 0xd800 && cp <= 0xdbff); } -UPB_INLINE const upb_MessageDef *google_protobuf_FieldDescriptorProto_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.FieldDescriptorProto"); +// Returns true iff a codepoint is the value for a low surrogate. +UPB_INLINE bool upb_Unicode_IsLow(uint32_t cp) { + return (cp >= 0xdc00 && cp <= 0xdfff); } -UPB_INLINE const upb_MessageDef *google_protobuf_OneofDescriptorProto_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.OneofDescriptorProto"); +// Returns the high 16-bit surrogate value for a supplementary codepoint. +// Does not sanity-check the input. +UPB_INLINE uint16_t upb_Unicode_ToHigh(uint32_t cp) { + return (cp >> 10) + 0xd7c0; } -UPB_INLINE const upb_MessageDef *google_protobuf_EnumDescriptorProto_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.EnumDescriptorProto"); +// Returns the low 16-bit surrogate value for a supplementary codepoint. +// Does not sanity-check the input. +UPB_INLINE uint16_t upb_Unicode_ToLow(uint32_t cp) { + return (cp & 0x3ff) | 0xdc00; } -UPB_INLINE const upb_MessageDef *google_protobuf_EnumDescriptorProto_EnumReservedRange_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.EnumDescriptorProto.EnumReservedRange"); +// Returns the 32-bit value corresponding to a pair of 16-bit surrogates. +// Does not sanity-check the input. +UPB_INLINE uint32_t upb_Unicode_FromPair(uint32_t high, uint32_t low) { + return ((high & 0x3ff) << 10) + (low & 0x3ff) + 0x10000; } -UPB_INLINE const upb_MessageDef *google_protobuf_EnumValueDescriptorProto_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.EnumValueDescriptorProto"); -} +// Outputs a codepoint as UTF8. +// Returns the number of bytes written (1-4 on success, 0 on error). +// Does not sanity-check the input. Specifically does not check for surrogates. +int upb_Unicode_ToUTF8(uint32_t cp, char* out); -UPB_INLINE const upb_MessageDef *google_protobuf_ServiceDescriptorProto_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.ServiceDescriptorProto"); -} +#ifdef __cplusplus +} /* extern "C" */ +#endif -UPB_INLINE const upb_MessageDef *google_protobuf_MethodDescriptorProto_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.MethodDescriptorProto"); -} -UPB_INLINE const upb_MessageDef *google_protobuf_FileOptions_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.FileOptions"); -} +#endif /* UPB_INTERNAL_UNICODE_H_ */ -UPB_INLINE const upb_MessageDef *google_protobuf_MessageOptions_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.MessageOptions"); -} +#ifndef UPB_REFLECTION_MESSAGE_H_ +#define UPB_REFLECTION_MESSAGE_H_ -UPB_INLINE const upb_MessageDef *google_protobuf_FieldOptions_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.FieldOptions"); -} -UPB_INLINE const upb_MessageDef *google_protobuf_OneofOptions_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.OneofOptions"); -} +// Must be last. -UPB_INLINE const upb_MessageDef *google_protobuf_EnumOptions_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.EnumOptions"); -} +#ifdef __cplusplus +extern "C" { +#endif -UPB_INLINE const upb_MessageDef *google_protobuf_EnumValueOptions_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.EnumValueOptions"); -} +upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f); -UPB_INLINE const upb_MessageDef *google_protobuf_ServiceOptions_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.ServiceOptions"); -} +/* Creates a new message of the given type in the given arena. */ +upb_Message* upb_Message_New(const upb_MessageDef* m, upb_Arena* a); -UPB_INLINE const upb_MessageDef *google_protobuf_MethodOptions_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.MethodOptions"); -} +/* Returns the value associated with this field. */ +upb_MessageValue upb_Message_Get(const upb_Message* msg, const upb_FieldDef* f); -UPB_INLINE const upb_MessageDef *google_protobuf_UninterpretedOption_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.UninterpretedOption"); +/* Returns a mutable pointer to a map, array, or submessage value. If the given + * arena is non-NULL this will construct a new object if it was not previously + * present. May not be called for primitive fields. */ +upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, + const upb_FieldDef* f, + upb_Arena* a); + +/* May only be called for fields where upb_FieldDef_HasPresence(f) == true. */ +bool upb_Message_Has(const upb_Message* msg, const upb_FieldDef* f); + +/* Returns the field that is set in the oneof, or NULL if none are set. */ +const upb_FieldDef* upb_Message_WhichOneof(const upb_Message* msg, + const upb_OneofDef* o); + +/* Sets the given field to the given value. For a msg/array/map/string, the + * caller must ensure that the target data outlives |msg| (by living either in + * the same arena or a different arena that outlives it). + * + * Returns false if allocation fails. */ +bool upb_Message_Set(upb_Message* msg, const upb_FieldDef* f, + upb_MessageValue val, upb_Arena* a); + +/* Clears any field presence and sets the value back to its default. */ +void upb_Message_ClearField(upb_Message* msg, const upb_FieldDef* f); + +/* Clear all data and unknown fields. */ +void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m); + +/* Iterate over present fields. + * + * size_t iter = kUpb_Message_Begin; + * const upb_FieldDef *f; + * upb_MessageValue val; + * while (upb_Message_Next(msg, m, ext_pool, &f, &val, &iter)) { + * process_field(f, val); + * } + * + * If ext_pool is NULL, no extensions will be returned. If the given symtab + * returns extensions that don't match what is in this message, those extensions + * will be skipped. + */ + +#define kUpb_Message_Begin -1 +bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, const upb_FieldDef** f, + upb_MessageValue* val, size_t* iter); + +/* Clears all unknown field data from this message and all submessages. */ +bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, + int maxdepth); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_MESSAGE_H_ */ + +#ifndef UPB_JSON_ENCODE_H_ +#define UPB_JSON_ENCODE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* When set, emits 0/default values. TODO(haberman): proto3 only? */ + upb_JsonEncode_EmitDefaults = 1 << 0, + + /* When set, use normal (snake_case) field names instead of JSON (camelCase) + names. */ + upb_JsonEncode_UseProtoNames = 1 << 1, + + /* When set, emits enums as their integer values instead of as their names. */ + upb_JsonEncode_FormatEnumsAsIntegers = 1 << 2 +}; + +/* Encodes the given |msg| to JSON format. The message's reflection is given in + * |m|. The symtab in |symtab| is used to find extensions (if NULL, extensions + * will not be printed). + * + * Output is placed in the given buffer, and always NULL-terminated. The output + * size (excluding NULL) is returned. This means that a return value >= |size| + * implies that the output was truncated. (These are the same semantics as + * snprintf()). */ +size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, int options, char* buf, + size_t size, upb_Status* status); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_JSONENCODE_H_ */ + +#ifndef UPB_INTERNAL_ENCODE_H_ +#define UPB_INTERNAL_ENCODE_H_ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Encodes a float or double that is round-trippable, but as short as possible. +// These routines are not fully optimal (not guaranteed to be shortest), but are +// short-ish and match the implementation that has been used in protobuf since +// the beginning. +// +// The given buffer size must be at least kUpb_RoundTripBufferSize. +enum { kUpb_RoundTripBufferSize = 32 }; +void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size); +void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_INTERNAL_ENCODE_H_ */ + +#ifndef UPB_INTERNAL_VSNPRINTF_COMPAT_H_ +#define UPB_INTERNAL_VSNPRINTF_COMPAT_H_ + +#include + +// Must be last. + +UPB_INLINE int _upb_vsnprintf(char* buf, size_t size, const char* fmt, + va_list ap) { +#if defined(__MINGW64__) || defined(__MINGW32__) || defined(_MSC_VER) + // The msvc runtime has a non-conforming vsnprintf() that requires the + // following compatibility code to become conformant. + int n = -1; + if (size != 0) n = _vsnprintf_s(buf, size, _TRUNCATE, fmt, ap); + if (n == -1) n = _vscprintf(fmt, ap); + return n; +#else + return vsnprintf(buf, size, fmt, ap); +#endif } -UPB_INLINE const upb_MessageDef *google_protobuf_UninterpretedOption_NamePart_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.UninterpretedOption.NamePart"); -} -UPB_INLINE const upb_MessageDef *google_protobuf_SourceCodeInfo_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.SourceCodeInfo"); -} +#endif // UPB_INTERNAL_VSNPRINTF_COMPAT_H_ -UPB_INLINE const upb_MessageDef *google_protobuf_SourceCodeInfo_Location_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.SourceCodeInfo.Location"); -} +#ifndef UPB_MINI_TABLE_H_ +#define UPB_MINI_TABLE_H_ -UPB_INLINE const upb_MessageDef *google_protobuf_GeneratedCodeInfo_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.GeneratedCodeInfo"); -} -UPB_INLINE const upb_MessageDef *google_protobuf_GeneratedCodeInfo_Annotation_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.GeneratedCodeInfo.Annotation"); -} +// Must be last. #ifdef __cplusplus -} /* extern "C" */ +extern "C" { #endif +const upb_MiniTable_Field* upb_MiniTable_FindFieldByNumber( + const upb_MiniTable* table, uint32_t number); -#endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPBDEFS_H_ */ +UPB_INLINE const upb_MiniTable* upb_MiniTable_GetSubMessageTable( + const upb_MiniTable* mini_table, const upb_MiniTable_Field* field) { + return mini_table->subs[field->submsg_index].submsg; +} -/** upb/reflection.h ************************************************************/ -#ifndef UPB_REFLECTION_H_ -#define UPB_REFLECTION_H_ +UPB_INLINE const upb_MiniTable_Enum* upb_MiniTable_GetSubEnumTable( + const upb_MiniTable* mini_table, const upb_MiniTable_Field* field) { + return mini_table->subs[field->submsg_index].subenum; +} +/** upb_MtDataEncoder *********************************************************/ -#ifdef __cplusplus -extern "C" { -#endif +// Functions to encode a string in a format that can be loaded by +// upb_MiniTable_Build(). -typedef union { - bool bool_val; - float float_val; - double double_val; - int32_t int32_val; - int64_t int64_val; - uint32_t uint32_val; - uint64_t uint64_val; - const upb_Map* map_val; - const upb_Message* msg_val; - const upb_Array* array_val; - upb_StringView str_val; -} upb_MessageValue; +typedef enum { + kUpb_MessageModifier_ValidateUtf8 = 1 << 0, + kUpb_MessageModifier_DefaultIsPacked = 1 << 1, + kUpb_MessageModifier_IsExtendable = 1 << 2, +} kUpb_MessageModifier; -typedef union { - upb_Map* map; - upb_Message* msg; - upb_Array* array; -} upb_MutableMessageValue; +typedef enum { + kUpb_FieldModifier_IsRepeated = 1 << 0, + kUpb_FieldModifier_IsPacked = 1 << 1, + kUpb_FieldModifier_IsClosedEnum = 1 << 2, + kUpb_FieldModifier_IsProto3Singular = 1 << 3, + kUpb_FieldModifier_IsRequired = 1 << 4, +} kUpb_FieldModifier; -upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f); +typedef struct { + char* end; // Limit of the buffer passed as a parameter. + // Aliased to internal-only members in .cc. + char internal[32]; +} upb_MtDataEncoder; -/** upb_Message - * *******************************************************************/ +// If the input buffer has at least this many bytes available, the encoder call +// is guaranteed to succeed (as long as field number order is maintained). +#define kUpb_MtDataEncoder_MinSize 16 -/* Creates a new message of the given type in the given arena. */ -upb_Message* upb_Message_New(const upb_MessageDef* m, upb_Arena* a); +// Encodes field/oneof information for a given message. The sequence of calls +// should look like: +// +// upb_MtDataEncoder e; +// char buf[256]; +// char* ptr = buf; +// e.end = ptr + sizeof(buf); +// unit64_t msg_mod = ...; // bitwise & of kUpb_MessageModifiers or zero +// ptr = upb_MtDataEncoder_StartMessage(&e, ptr, msg_mod); +// // Fields *must* be in field number order. +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// +// // If oneofs are present. Oneofs must be encoded after regular fields. +// ptr = upb_MiniTable_StartOneof(&e, ptr) +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// +// ptr = upb_MiniTable_StartOneof(&e, ptr); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// +// Oneofs must be encoded after all regular fields. +char* upb_MtDataEncoder_StartMessage(upb_MtDataEncoder* e, char* ptr, + uint64_t msg_mod); +char* upb_MtDataEncoder_PutField(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod); +char* upb_MtDataEncoder_StartOneof(upb_MtDataEncoder* e, char* ptr); +char* upb_MtDataEncoder_PutOneofField(upb_MtDataEncoder* e, char* ptr, + uint32_t field_num); + +// Encodes the set of values for a given enum. The values must be given in +// order (after casting to uint32_t), and repeats are not allowed. +void upb_MtDataEncoder_StartEnum(upb_MtDataEncoder* e); +char* upb_MtDataEncoder_PutEnumValue(upb_MtDataEncoder* e, char* ptr, + uint32_t val); +char* upb_MtDataEncoder_EndEnum(upb_MtDataEncoder* e, char* ptr); -/* Returns the value associated with this field. */ -upb_MessageValue upb_Message_Get(const upb_Message* msg, const upb_FieldDef* f); +/** upb_MiniTable *************************************************************/ -/* Returns a mutable pointer to a map, array, or submessage value. If the given - * arena is non-NULL this will construct a new object if it was not previously - * present. May not be called for primitive fields. */ -upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, - const upb_FieldDef* f, - upb_Arena* a); +typedef enum { + kUpb_MiniTablePlatform_32Bit, + kUpb_MiniTablePlatform_64Bit, + kUpb_MiniTablePlatform_Native = + UPB_SIZE(kUpb_MiniTablePlatform_32Bit, kUpb_MiniTablePlatform_64Bit), +} upb_MiniTablePlatform; + +// Builds a mini table from the data encoded in the buffer [data, len]. If any +// errors occur, returns NULL and sets a status message. In the success case, +// the caller must call upb_MiniTable_SetSub*() for all message or proto2 enum +// fields to link the table to the appropriate sub-tables. +upb_MiniTable* upb_MiniTable_Build(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, upb_Status* status); + +// Links a sub-message field to a MiniTable for that sub-message. If a +// sub-message field is not linked, it will be treated as an unknown field +// during parsing, and setting the field will not be allowed. It is possible +// to link the message field later, at which point it will no longer be treated +// as unknown. However there is no synchronization for this operation, which +// means parallel mutation requires external synchronization. +void upb_MiniTable_SetSubMessage(upb_MiniTable* table, + upb_MiniTable_Field* field, + const upb_MiniTable* sub); + +// Links an enum field to a MiniTable for that enum. All enum fields must +// be linked prior to parsing. +void upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTable_Field* field, + const upb_MiniTable_Enum* sub); + +const char* upb_MiniTable_BuildExtension(const char* data, size_t len, + upb_MiniTable_Extension* ext, + const upb_MiniTable* extendee, + upb_MiniTable_Sub sub, + upb_Status* status); + +// Special-case functions for MessageSet layout and map entries. +upb_MiniTable* upb_MiniTable_BuildMessageSet(upb_MiniTablePlatform platform, + upb_Arena* arena); +upb_MiniTable* upb_MiniTable_BuildMapEntry(upb_FieldType key_type, + upb_FieldType value_type, + bool value_is_proto3_enum, + upb_MiniTablePlatform platform, + upb_Arena* arena); + +upb_MiniTable_Enum* upb_MiniTable_BuildEnum(const char* data, size_t len, + upb_Arena* arena, + upb_Status* status); + +// Like upb_MiniTable_Build(), but the user provides a buffer of layout data so +// it can be reused from call to call, avoiding repeated realloc()/free(). +// +// The caller owns `*buf` both before and after the call, and must free() it +// when it is no longer in use. The function will realloc() `*buf` as +// necessary, updating `*size` accordingly. +upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, void** buf, + size_t* buf_size, upb_Status* status); + +// For testing only. +char upb_ToBase92(int8_t ch); +char upb_FromBase92(uint8_t ch); +bool upb_IsTypePackable(upb_FieldType type); -/* May only be called for fields where upb_FieldDef_HasPresence(f) == true. */ -bool upb_Message_Has(const upb_Message* msg, const upb_FieldDef* f); +#ifdef __cplusplus +} /* extern "C" */ +#endif -/* Returns the field that is set in the oneof, or NULL if none are set. */ -const upb_FieldDef* upb_Message_WhichOneof(const upb_Message* msg, - const upb_OneofDef* o); -/* Sets the given field to the given value. For a msg/array/map/string, the - * caller must ensure that the target data outlives |msg| (by living either in - * the same arena or a different arena that outlives it). - * - * Returns false if allocation fails. */ -bool upb_Message_Set(upb_Message* msg, const upb_FieldDef* f, - upb_MessageValue val, upb_Arena* a); +#endif /* UPB_MINI_TABLE_H_ */ -/* Clears any field presence and sets the value back to its default. */ -void upb_Message_ClearField(upb_Message* msg, const upb_FieldDef* f); +#ifndef UPB_REFLECTION_DEF_BUILDER_H_ +#define UPB_REFLECTION_DEF_BUILDER_H_ -/* Clear all data and unknown fields. */ -void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m); -/* Iterate over present fields. - * - * size_t iter = kUpb_Message_Begin; - * const upb_FieldDef *f; - * upb_MessageValue val; - * while (upb_Message_Next(msg, m, ext_pool, &f, &val, &iter)) { - * process_field(f, val); - * } - * - * If ext_pool is NULL, no extensions will be returned. If the given symtab - * returns extensions that don't match what is in this message, those extensions - * will be skipped. - */ +// Must be last. -#define kUpb_Message_Begin -1 -bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, - const upb_DefPool* ext_pool, const upb_FieldDef** f, - upb_MessageValue* val, size_t* iter); +// We want to copy the options verbatim into the destination options proto. +// We use serialize+parse as our deep copy. +#define UBP_DEF_SET_OPTIONS(target, desc_type, options_type, proto) \ + if (google_protobuf_##desc_type##_has_options(proto)) { \ + size_t size; \ + char* pb = google_protobuf_##options_type##_serialize( \ + google_protobuf_##desc_type##_options(proto), ctx->tmp_arena, &size); \ + if (!pb) _upb_DefBuilder_OomErr(ctx); \ + target = \ + google_protobuf_##options_type##_parse(pb, size, _upb_DefBuilder_Arena(ctx)); \ + if (!target) _upb_DefBuilder_OomErr(ctx); \ + } else { \ + target = (const google_protobuf_##options_type*)kUpbDefOptDefault; \ + } -/* Clears all unknown field data from this message and all submessages. */ -bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, - int maxdepth); +#ifdef __cplusplus +extern "C" { +#endif -/** upb_Array *****************************************************************/ +struct upb_DefBuilder { + upb_DefPool* symtab; + upb_FileDef* file; // File we are building. + upb_Arena* arena; // Allocate defs here. + upb_Arena* tmp_arena; // For temporary allocations. + upb_Status* status; // Record errors here. + const upb_MiniTable_File* layout; // NULL if we should build layouts. + int enum_count; // Count of enums built so far. + int msg_count; // Count of messages built so far. + int ext_count; // Count of extensions built so far. + jmp_buf err; // longjmp() on error. +}; -/* Creates a new array on the given arena that holds elements of this type. */ -upb_Array* upb_Array_New(upb_Arena* a, upb_CType type); +extern const char* kUpbDefOptDefault; -/* Returns the size of the array. */ -size_t upb_Array_Size(const upb_Array* arr); +// ctx->status has already been set elsewhere so just fail/longjmp() +UPB_NORETURN void _upb_DefBuilder_FailJmp(upb_DefBuilder* ctx); -/* Returns the given element, which must be within the array's current size. */ -upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i); +UPB_NORETURN void _upb_DefBuilder_Errf(upb_DefBuilder* ctx, const char* fmt, + ...) UPB_PRINTF(2, 3); +UPB_NORETURN void _upb_DefBuilder_OomErr(upb_DefBuilder* ctx); -/* Sets the given element, which must be within the array's current size. */ -void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val); +const char* _upb_DefBuilder_MakeFullName(upb_DefBuilder* ctx, + const char* prefix, + upb_StringView name); -/* Appends an element to the array. Returns false on allocation failure. */ -bool upb_Array_Append(upb_Array* array, upb_MessageValue val, upb_Arena* arena); +// Given a symbol and the base symbol inside which it is defined, +// find the symbol's definition. +const void* _upb_DefBuilder_ResolveAny(upb_DefBuilder* ctx, + const char* from_name_dbg, + const char* base, upb_StringView sym, + upb_deftype_t* type); -/* Moves elements within the array using memmove(). Like memmove(), the source - * and destination elements may be overlapping. */ -void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx, - size_t count); +const void* _upb_DefBuilder_Resolve(upb_DefBuilder* ctx, + const char* from_name_dbg, const char* base, + upb_StringView sym, upb_deftype_t type); -/* Inserts one or more empty elements into the array. Existing elements are - * shifted right. The new elements have undefined state and must be set with - * `upb_Array_Set()`. - * REQUIRES: `i <= upb_Array_Size(arr)` */ -bool upb_Array_Insert(upb_Array* array, size_t i, size_t count, - upb_Arena* arena); +char _upb_DefBuilder_ParseEscape(upb_DefBuilder* ctx, const upb_FieldDef* f, + const char** src, const char* end); -/* Deletes one or more elements from the array. Existing elements are shifted - * left. - * REQUIRES: `i + count <= upb_Array_Size(arr)` */ -void upb_Array_Delete(upb_Array* array, size_t i, size_t count); +const char* _upb_DefBuilder_FullToShort(const char* fullname); -/* Changes the size of a vector. New elements are initialized to empty/0. - * Returns false on allocation failure. */ -bool upb_Array_Resize(upb_Array* array, size_t size, upb_Arena* arena); +UPB_INLINE void* _upb_DefBuilder_Alloc(upb_DefBuilder* ctx, size_t bytes) { + if (bytes == 0) return NULL; + void* ret = upb_Arena_Malloc(ctx->arena, bytes); + if (!ret) _upb_DefBuilder_OomErr(ctx); + return ret; +} -/** upb_Map *******************************************************************/ +// Adds a symbol |v| to the symtab, which must be a def pointer previously +// packed with pack_def(). The def's pointer to upb_FileDef* must be set before +// adding, so we know which entries to remove if building this file fails. +UPB_INLINE void _upb_DefBuilder_Add(upb_DefBuilder* ctx, const char* name, + upb_value v) { + upb_StringView sym = {.data = name, .size = strlen(name)}; + bool ok = _upb_DefPool_InsertSym(ctx->symtab, sym, v, ctx->status); + if (!ok) _upb_DefBuilder_FailJmp(ctx); +} -/* Creates a new map on the given arena with the given key/value size. */ -upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type); +UPB_INLINE upb_Arena* _upb_DefBuilder_Arena(const upb_DefBuilder* ctx) { + return ctx->arena; +} -/* Returns the number of entries in the map. */ -size_t upb_Map_Size(const upb_Map* map); +UPB_INLINE upb_FileDef* _upb_DefBuilder_File(const upb_DefBuilder* ctx) { + return ctx->file; +} -/* Stores a value for the given key into |*val| (or the zero value if the key is - * not present). Returns whether the key was present. The |val| pointer may be - * NULL, in which case the function tests whether the given key is present. */ -bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, - upb_MessageValue* val); +// This version of CheckIdent() is only called by other, faster versions after +// they detect a parsing error. +void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name, + bool full); -/* Removes all entries in the map. */ -void upb_Map_Clear(upb_Map* map); +// Verify a relative identifier string. The loop is branchless for speed. +UPB_INLINE void _upb_DefBuilder_CheckIdentNotFull(upb_DefBuilder* ctx, + upb_StringView name) { + bool good = name.size > 0; -/* Sets the given key to the given value. Returns true if this was a new key in - * the map, or false if an existing key was replaced. */ -bool upb_Map_Set(upb_Map* map, upb_MessageValue key, upb_MessageValue val, - upb_Arena* arena); + for (size_t i = 0; i < name.size; i++) { + const char c = name.data[i]; + const char d = c | 0x20; // force lowercase + const bool is_alpha = (('a' <= d) & (d <= 'z')) | (c == '_'); + const bool is_numer = ('0' <= c) & (c <= '9') & (i != 0); -/* Deletes this key from the table. Returns true if the key was present. */ -bool upb_Map_Delete(upb_Map* map, upb_MessageValue key); + good &= is_alpha | is_numer; + } -/* Map iteration: - * - * size_t iter = kUpb_Map_Begin; - * while (upb_MapIterator_Next(map, &iter)) { - * upb_MessageValue key = upb_MapIterator_Key(map, iter); - * upb_MessageValue val = upb_MapIterator_Value(map, iter); - * - * // If mutating is desired. - * upb_MapIterator_SetValue(map, iter, value2); - * } - */ + if (!good) _upb_DefBuilder_CheckIdentSlow(ctx, name, false); +} -/* Advances to the next entry. Returns false if no more entries are present. */ -bool upb_MapIterator_Next(const upb_Map* map, size_t* iter); +// Verify a full identifier string. This is slightly more complicated than +// verifying a relative identifier string because we must track '.' chars. +UPB_INLINE void _upb_DefBuilder_CheckIdentFull(upb_DefBuilder* ctx, + upb_StringView name) { + bool good = name.size > 0; + bool start = true; -/* Returns true if the iterator still points to a valid entry, or false if the - * iterator is past the last element. It is an error to call this function with - * kUpb_Map_Begin (you must call next() at least once first). */ -bool upb_MapIterator_Done(const upb_Map* map, size_t iter); + for (size_t i = 0; i < name.size; i++) { + const char c = name.data[i]; + const char d = c | 0x20; // force lowercase + const bool is_alpha = (('a' <= d) & (d <= 'z')) | (c == '_'); + const bool is_numer = ('0' <= c) & (c <= '9') & !start; + const bool is_dot = (c == '.') & !start; -/* Returns the key and value for this entry of the map. */ -upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter); -upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter); + good &= is_alpha | is_numer | is_dot; + start = is_dot; + } -/* Sets the value for this entry. The iterator must not be done, and the - * iterator must not have been initialized const. */ -void upb_MapIterator_SetValue(upb_Map* map, size_t iter, - upb_MessageValue value); + if (!good) _upb_DefBuilder_CheckIdentSlow(ctx, name, true); +} #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_REFLECTION_H_ */ +#endif /* UPB_REFLECTION_DEF_BUILDER_H_ */ + +#ifndef UPB_REFLECTION_DESC_STATE_H_ +#define UPB_REFLECTION_DESC_STATE_H_ + -/** upb/json_decode.h ************************************************************/ -#ifndef UPB_JSONDECODE_H_ -#define UPB_JSONDECODE_H_ +// Must be last. +// Manages the storage for mini descriptor strings as they are being encoded. +// TODO(b/234740652): Move some of this state directly into the encoder, maybe. +typedef struct { + upb_MtDataEncoder e; + size_t bufsize; + char* buf; + char* ptr; +} upb_DescState; #ifdef __cplusplus extern "C" { #endif -enum { upb_JsonDecode_IgnoreUnknown = 1 }; +UPB_INLINE void _upb_DescState_Init(upb_DescState* d) { + d->bufsize = kUpb_MtDataEncoder_MinSize * 2; + d->buf = NULL; + d->ptr = NULL; +} -bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, - const upb_MessageDef* m, const upb_DefPool* symtab, - int options, upb_Arena* arena, upb_Status* status); +bool _upb_DescState_Grow(upb_DescState* d, upb_Arena* a); #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_JSONDECODE_H_ */ -/** upb/json_encode.h ************************************************************/ -#ifndef UPB_JSONENCODE_H_ -#define UPB_JSONENCODE_H_ +#endif /* UPB_REFLECTION_DESC_STATE_H_ */ +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +#ifndef UPB_MAP_SORTER_H_ +#define UPB_MAP_SORTER_H_ + + +// Must be last. #ifdef __cplusplus extern "C" { #endif -enum { - /* When set, emits 0/default values. TODO(haberman): proto3 only? */ - upb_JsonEncode_EmitDefaults = 1, +// _upb_mapsorter sorts maps and provides ordered iteration over the entries. +// Since maps can be recursive (map values can be messages which contain other +// maps), _upb_mapsorter can contain a stack of maps. - /* When set, use normal (snake_caes) field names instead of JSON (camelCase) - names. */ - upb_JsonEncode_UseProtoNames = 2 -}; +typedef struct { + upb_tabent const** entries; + int size; + int cap; +} _upb_mapsorter; -/* Encodes the given |msg| to JSON format. The message's reflection is given in - * |m|. The symtab in |symtab| is used to find extensions (if NULL, extensions - * will not be printed). - * - * Output is placed in the given buffer, and always NULL-terminated. The output - * size (excluding NULL) is returned. This means that a return value >= |size| - * implies that the output was truncated. (These are the same semantics as - * snprintf()). */ -size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, - const upb_DefPool* ext_pool, int options, char* buf, - size_t size, upb_Status* status); +typedef struct { + int start; + int pos; + int end; +} _upb_sortedmap; + +UPB_INLINE void _upb_mapsorter_init(_upb_mapsorter* s) { + s->entries = NULL; + s->size = 0; + s->cap = 0; +} + +UPB_INLINE void _upb_mapsorter_destroy(_upb_mapsorter* s) { + if (s->entries) free(s->entries); +} + +UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter* s, const upb_Map* map, + _upb_sortedmap* sorted, upb_MapEntry* ent) { + if (sorted->pos == sorted->end) return false; + const upb_tabent* tabent = s->entries[sorted->pos++]; + upb_StringView key = upb_tabstrview(tabent->key); + _upb_map_fromkey(key, &ent->k, map->key_size); + upb_value val = {tabent->val.val}; + _upb_map_fromvalue(val, &ent->v, map->val_size); + return true; +} + +UPB_INLINE void _upb_mapsorter_popmap(_upb_mapsorter* s, + _upb_sortedmap* sorted) { + s->size = sorted->start; +} + +bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, + const upb_Map* map, _upb_sortedmap* sorted); #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_JSONENCODE_H_ */ -/** upb/port_undef.inc ************************************************************/ +#endif /* UPB_MAP_SORTER_H_ */ + /* See port_def.inc. This should #undef all macros #defined there. */ #undef UPB_SIZE @@ -5448,6 +7435,7 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #undef UPB_ALIGN_DOWN #undef UPB_ALIGN_MALLOC #undef UPB_ALIGN_OF +#undef UPB_MALLOC_ALIGN #undef UPB_LIKELY #undef UPB_UNLIKELY #undef UPB_FORCEINLINE @@ -5470,3 +7458,6 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #undef UPB_POISON_MEMORY_REGION #undef UPB_UNPOISON_MEMORY_REGION #undef UPB_ASAN +#undef UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 +#undef UPB_DEPRECATED +#undef UPB_GNUC_MIN diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h index 4f14ab526a..77b61c2358 100644 --- a/php/ext/google/protobuf/protobuf.h +++ b/php/ext/google/protobuf/protobuf.h @@ -127,7 +127,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_setter, 0, 0, 1) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() -#define PHP_PROTOBUF_VERSION "3.21.6" +#define PHP_PROTOBUF_VERSION "3.21.7" // ptr -> PHP object cache. This is a weak map that caches lazily-created // wrapper objects around upb types: diff --git a/php/src/Google/Protobuf/Internal/Message.php b/php/src/Google/Protobuf/Internal/Message.php index 1d1fbf27c5..f412b419c8 100644 --- a/php/src/Google/Protobuf/Internal/Message.php +++ b/php/src/Google/Protobuf/Internal/Message.php @@ -54,6 +54,7 @@ use Google\Protobuf\NullValue; * or extend this class or its child classes by their own. See the comment of * specific functions for more details. */ +#[\AllowDynamicProperties] class Message { @@ -1980,8 +1981,12 @@ class Message $size += 9; $size += $value_msg->jsonByteSize(); } else { - // Size for value. +1 for comma, -2 for "{}". - $size += $value_msg->jsonByteSize() -1; + $value_size = $value_msg->jsonByteSize(); + // size === 2 it's empty message {} which is not serialized inside any + if ($value_size !== 2) { + // Size for value. +1 for comma, -2 for "{}". + $size += $value_size -1; + } } } elseif (get_class($this) === 'Google\Protobuf\FieldMask') { $field_mask = GPBUtil::formatFieldMask($this); diff --git a/php/tests/EncodeDecodeTest.php b/php/tests/EncodeDecodeTest.php index 33d8da1795..70748e1091 100644 --- a/php/tests/EncodeDecodeTest.php +++ b/php/tests/EncodeDecodeTest.php @@ -5,6 +5,7 @@ require_once('test_util.php'); use Google\Protobuf\RepeatedField; use Google\Protobuf\GPBType; +use Foo\EmptyAnySerialization; use Foo\TestInt32Value; use Foo\TestInt64Value; use Foo\TestUInt32Value; @@ -1513,4 +1514,22 @@ class EncodeDecodeTest extends TestBase [TestStringValue::class, "a", "\"a\"", "", "\"\""], ]; } + + public function testEmptyAnySerialization() + { + $m = new EmptyAnySerialization(); + + $any = new Any(); + $any->pack($m); + + $data = $any->serializeToJsonString(); + $this->assertEquals('{"@type":"type.googleapis.com/foo.EmptyAnySerialization"}', $data); + + $any = new Any(); + $any->mergeFromJsonString($data); + + $m = $any->unpack(); + $this->assertInstanceOf(EmptyAnySerialization::class, $m); + $this->assertEquals('', $m->getA()); + } } diff --git a/php/tests/proto/test.proto b/php/tests/proto/test.proto index 421292ab52..4217800507 100644 --- a/php/tests/proto/test.proto +++ b/php/tests/proto/test.proto @@ -168,6 +168,10 @@ message ARRAY { int32 a = 1; } +message EmptyAnySerialization { + string a = 1; +} + message TestPackedMessage { repeated int32 repeated_int32 = 90 [packed = true]; repeated int64 repeated_int64 = 91 [packed = true]; diff --git a/pkg/BUILD.bazel b/pkg/BUILD.bazel index 34e60d6c15..ee300f6334 100644 --- a/pkg/BUILD.bazel +++ b/pkg/BUILD.bazel @@ -6,14 +6,9 @@ load( "pkg_files", "strip_prefix", ) -load("//:protobuf_release.bzl", "package_naming") load(":build_systems.bzl", "gen_file_lists") load(":cc_dist_library.bzl", "cc_dist_library") -package_naming( - name = "protobuf_pkg_naming", -) - pkg_files( name = "wkt_protos_files", srcs = [ @@ -375,6 +370,7 @@ cc_dist_library( "//src/google/protobuf/io:printer", "//src/google/protobuf/io:tokenizer", "//src/google/protobuf/io:zero_copy_sink", + "//src/google/protobuf/json", "//src/google/protobuf/stubs", "//src/google/protobuf/stubs:lite", "//src/google/protobuf/util:delimited_message_util", @@ -383,15 +379,6 @@ cc_dist_library( "//src/google/protobuf/util:json_util", "//src/google/protobuf/util:time_util", "//src/google/protobuf/util:type_resolver_util", - "//src/google/protobuf/util/internal:constants", - "//src/google/protobuf/util/internal:datapiece", - "//src/google/protobuf/util/internal:default_value", - "//src/google/protobuf/util/internal:field_mask_utility", - "//src/google/protobuf/util/internal:json", - "//src/google/protobuf/util/internal:object_writer", - "//src/google/protobuf/util/internal:protostream", - "//src/google/protobuf/util/internal:type_info", - "//src/google/protobuf/util/internal:utility", ], ) @@ -410,6 +397,7 @@ cc_dist_library( "//src/google/protobuf/compiler/java:names", "//src/google/protobuf/compiler/java:names_internal", "//src/google/protobuf/compiler/objectivec", + "//src/google/protobuf/compiler/objectivec:line_consumer", "//src/google/protobuf/compiler/objectivec:names", "//src/google/protobuf/compiler/objectivec:names_internal", "//src/google/protobuf/compiler/php", @@ -433,9 +421,6 @@ cc_dist_library( deps = [ "//src/google/protobuf:test_util", "//src/google/protobuf:test_util2", - "//src/google/protobuf/util/internal:expecting_objectwriter", - "//src/google/protobuf/util/internal:mock_error_listener", - "//src/google/protobuf/util/internal:type_info_test_helper", "//src/google/protobuf/compiler:annotation_test_util", "//src/google/protobuf/compiler/cpp:unittest_lib", ], diff --git a/pkg/build_systems.bzl b/pkg/build_systems.bzl index cb8ad11505..ce6d42959c 100644 --- a/pkg/build_systems.bzl +++ b/pkg/build_systems.bzl @@ -19,6 +19,7 @@ def gen_file_lists(name, out_stem, **kwargs): srcs = [ out_stem + ".cmake", ], + visibility = ["//src:__pkg__"], ) ################################################################################ diff --git a/protobuf_deps.bzl b/protobuf_deps.bzl index 427f29fb60..34e0a4c710 100644 --- a/protobuf_deps.bzl +++ b/protobuf_deps.bzl @@ -49,9 +49,9 @@ def protobuf_deps(): http_archive( name = "zlib", build_file = "@com_google_protobuf//:third_party/zlib.BUILD", - sha256 = "629380c90a77b964d896ed37163f5c3a34f6e6d897311f1df2a7016355c45eff", - strip_prefix = "zlib-1.2.11", - urls = ["https://github.com/madler/zlib/archive/v1.2.11.tar.gz"], + sha256 = "d8688496ea40fb61787500e863cc63c9afcbc524468cedeb478068924eb54932", + strip_prefix = "zlib-1.2.12", + urls = ["https://github.com/madler/zlib/archive/v1.2.12.tar.gz"], ) if not native.existing_rule("rules_cc"): @@ -115,6 +115,6 @@ def protobuf_deps(): _github_archive( name = "upb", repo = "https://github.com/protocolbuffers/upb", - commit = "5485645125ba3783ae2b597bd7b77679721cb1c6", - sha256 = "86de85c58eb3cb04b0987a7642ce84e55629f704ab4a9a0210a660a1115f1dd0", + commit = "32c6e9baab03d584b85390fdba789118f20613fc", + #sha256 = "4c82bff4f790dbb5a11ec40b1fac44e7c95d9a63fd215a13aaf44cb27b10ac27", ) diff --git a/protobuf_version.bzl b/protobuf_version.bzl index fdd9b5fe57..bf6ec169ac 100644 --- a/protobuf_version.bzl +++ b/protobuf_version.bzl @@ -1,3 +1,3 @@ -PROTOC_VERSION = '21.6' -PROTOBUF_JAVA_VERSION = '3.21.6' -PROTOBUF_PYTHON_VERSION = '4.21.6' +PROTOC_VERSION = "21.7" +PROTOBUF_JAVA_VERSION = "3.21.7" +PROTOBUF_PYTHON_VERSION = "4.21.7" diff --git a/python/BUILD.bazel b/python/BUILD.bazel index 118bb4d6af..ffaf988be1 100644 --- a/python/BUILD.bazel +++ b/python/BUILD.bazel @@ -8,6 +8,7 @@ load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix") load("@rules_python//python:defs.bzl", "py_library") +load("@pip_deps//:requirements.bzl", "requirement") load("//:protobuf.bzl", "internal_py_proto_library") load("//build_defs:cpp_opts.bzl", "COPTS") load("//conformance:defs.bzl", "conformance_test") @@ -319,6 +320,16 @@ py_test( deps = [":python_test_lib"], ) +py_test( + name = "numpy_test", + srcs = ["google/protobuf/internal/numpy_test.py"], + imports = ["."], + deps = [ + ":python_test_lib", + requirement("numpy"), + ], +) + py_test( name = "proto_builder_test", srcs = ["google/protobuf/internal/proto_builder_test.py"], diff --git a/python/google/protobuf/__init__.py b/python/google/protobuf/__init__.py index 9ba2b78c85..70d564a90a 100644 --- a/python/google/protobuf/__init__.py +++ b/python/google/protobuf/__init__.py @@ -30,4 +30,4 @@ # Copyright 2007 Google Inc. All Rights Reserved. -__version__ = '4.21.6' +__version__ = '4.21.7' diff --git a/python/google/protobuf/internal/descriptor_pool_test.py b/python/google/protobuf/internal/descriptor_pool_test.py index efd909a1be..2916453578 100644 --- a/python/google/protobuf/internal/descriptor_pool_test.py +++ b/python/google/protobuf/internal/descriptor_pool_test.py @@ -414,6 +414,20 @@ class DescriptorPoolTestBase(object): field = file_json.message_types_by_name['class'].fields_by_name['int_field'] self.assertEqual(field.json_name, 'json_int') + def testAddSerializedFileTwice(self): + if isinstance(self, SecondaryDescriptorFromDescriptorDB): + if api_implementation.Type() != 'python': + # Cpp extension cannot call Add on a DescriptorPool + # that uses a DescriptorDatabase. + # TODO(jieluo): Fix python and cpp extension diff. + return + self.pool = descriptor_pool.DescriptorPool() + file1_first = self.pool.AddSerializedFile( + self.factory_test1_fd.SerializeToString()) + file1_again = self.pool.AddSerializedFile( + self.factory_test1_fd.SerializeToString()) + self.assertIs(file1_first, file1_again) + def testEnumDefaultValue(self): """Test the default value of enums which don't start at zero.""" def _CheckDefaultValue(file_descriptor): diff --git a/python/google/protobuf/internal/numpy_test.py b/python/google/protobuf/internal/numpy_test.py new file mode 100644 index 0000000000..38175781ed --- /dev/null +++ b/python/google/protobuf/internal/numpy_test.py @@ -0,0 +1,215 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2008 Google Inc. All rights reserved. +# https://developers.google.com/protocol-buffers/ +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Test use of numpy types with repeated and non-repeated scalar fields.""" + +import unittest + +import numpy as np + +from google.protobuf import unittest_pb2 +from google.protobuf.internal import testing_refleaks + +message = unittest_pb2.TestAllTypes() +np_float_scalar = np.float64(0.0) +np_1_float_array = np.zeros(shape=(1,), dtype=np.float64) +np_2_float_array = np.zeros(shape=(2,), dtype=np.float64) +np_11_float_array = np.zeros(shape=(1, 1), dtype=np.float64) +np_22_float_array = np.zeros(shape=(2, 2), dtype=np.float64) + +np_int_scalar = np.int64(0) +np_1_int_array = np.zeros(shape=(1,), dtype=np.int64) +np_2_int_array = np.zeros(shape=(2,), dtype=np.int64) +np_11_int_array = np.zeros(shape=(1, 1), dtype=np.int64) +np_22_int_array = np.zeros(shape=(2, 2), dtype=np.int64) + +np_uint_scalar = np.uint64(0) +np_1_uint_array = np.zeros(shape=(1,), dtype=np.uint64) +np_2_uint_array = np.zeros(shape=(2,), dtype=np.uint64) +np_11_uint_array = np.zeros(shape=(1, 1), dtype=np.uint64) +np_22_uint_array = np.zeros(shape=(2, 2), dtype=np.uint64) + +np_bool_scalar = np.bool_(False) +np_1_bool_array = np.zeros(shape=(1,), dtype=np.bool_) +np_2_bool_array = np.zeros(shape=(2,), dtype=np.bool_) +np_11_bool_array = np.zeros(shape=(1, 1), dtype=np.bool_) +np_22_bool_array = np.zeros(shape=(2, 2), dtype=np.bool_) + + +@testing_refleaks.TestCase +class NumpyIntProtoTest(unittest.TestCase): + + # Assigning dim 1 ndarray of ints to repeated field should pass + def testNumpyDim1IntArrayToRepeated_IsValid(self): + message.repeated_int64[:] = np_1_int_array + message.repeated_int64[:] = np_2_int_array + + message.repeated_uint64[:] = np_1_uint_array + message.repeated_uint64[:] = np_2_uint_array + + # Assigning dim 2 ndarray of ints to repeated field should fail + def testNumpyDim2IntArrayToRepeated_RaisesTypeError(self): + with self.assertRaises(TypeError): + message.repeated_int64[:] = np_11_int_array + with self.assertRaises(TypeError): + message.repeated_int64[:] = np_22_int_array + + with self.assertRaises(TypeError): + message.repeated_uint64[:] = np_11_uint_array + with self.assertRaises(TypeError): + message.repeated_uint64[:] = np_22_uint_array + + # Assigning any ndarray of floats to repeated int field should fail + def testNumpyFloatArrayToRepeated_RaisesTypeError(self): + with self.assertRaises(TypeError): + message.repeated_int64[:] = np_1_float_array + with self.assertRaises(TypeError): + message.repeated_int64[:] = np_11_float_array + with self.assertRaises(TypeError): + message.repeated_int64[:] = np_22_float_array + + # Assigning any np int to scalar field should pass + def testNumpyIntScalarToScalar_IsValid(self): + message.optional_int64 = np_int_scalar + message.optional_uint64 = np_uint_scalar + + # Assigning any ndarray of ints to scalar field should fail + def testNumpyIntArrayToScalar_RaisesTypeError(self): + with self.assertRaises(TypeError): + message.optional_int64 = np_1_int_array + with self.assertRaises(TypeError): + message.optional_int64 = np_11_int_array + with self.assertRaises(TypeError): + message.optional_int64 = np_22_int_array + + with self.assertRaises(TypeError): + message.optional_uint64 = np_1_uint_array + with self.assertRaises(TypeError): + message.optional_uint64 = np_11_uint_array + with self.assertRaises(TypeError): + message.optional_uint64 = np_22_uint_array + + # Assigning any ndarray of floats to scalar field should fail + def testNumpyFloatArrayToScalar_RaisesTypeError(self): + with self.assertRaises(TypeError): + message.optional_int64 = np_1_float_array + with self.assertRaises(TypeError): + message.optional_int64 = np_11_float_array + with self.assertRaises(TypeError): + message.optional_int64 = np_22_float_array + + +@testing_refleaks.TestCase +class NumpyFloatProtoTest(unittest.TestCase): + + # Assigning dim 1 ndarray of floats to repeated field should pass + def testNumpyDim1FloatArrayToRepeated_IsValid(self): + message.repeated_float[:] = np_1_float_array + message.repeated_float[:] = np_2_float_array + + # Assigning dim 2 ndarray of floats to repeated field should fail + def testNumpyDim2FloatArrayToRepeated_RaisesTypeError(self): + with self.assertRaises(TypeError): + message.repeated_float[:] = np_11_float_array + with self.assertRaises(TypeError): + message.repeated_float[:] = np_22_float_array + + # Assigning any np float to scalar field should pass + def testNumpyFloatScalarToScalar_IsValid(self): + message.optional_float = np_float_scalar + + # Assigning any ndarray of float to scalar field should fail + def testNumpyFloatArrayToScalar_RaisesTypeError(self): + with self.assertRaises(TypeError): + message.optional_float = np_1_float_array + with self.assertRaises(TypeError): + message.optional_float = np_11_float_array + with self.assertRaises(TypeError): + message.optional_float = np_22_float_array + + +@testing_refleaks.TestCase +class NumpyBoolProtoTest(unittest.TestCase): + + # Assigning dim 1 ndarray of bool to repeated field should pass + def testNumpyDim1BoolArrayToRepeated_IsValid(self): + message.repeated_bool[:] = np_1_bool_array + message.repeated_bool[:] = np_2_bool_array + + # Assigning dim 2 ndarray of bool to repeated field should fail + def testNumpyDim2BoolArrayToRepeated_RaisesTypeError(self): + with self.assertRaises(TypeError): + message.repeated_bool[:] = np_11_bool_array + with self.assertRaises(TypeError): + message.repeated_bool[:] = np_22_bool_array + + # Assigning any np bool to scalar field should pass + def testNumpyBoolScalarToScalar_IsValid(self): + message.optional_bool = np_bool_scalar + + # Assigning any ndarray of bool to scalar field should fail + def testNumpyBoolArrayToScalar_RaisesTypeError(self): + with self.assertRaises(TypeError): + message.optional_bool = np_1_bool_array + with self.assertRaises(TypeError): + message.optional_bool = np_11_bool_array + with self.assertRaises(TypeError): + message.optional_bool = np_22_bool_array + + +@testing_refleaks.TestCase +class NumpyProtoIndexingTest(unittest.TestCase): + + def testNumpyIntScalarIndexing_Passes(self): + data = unittest_pb2.TestAllTypes(repeated_int64=[0, 1, 2]) + self.assertEqual(0, data.repeated_int64[np.int64(0)]) + + def testNumpyNegative1IntScalarIndexing_Passes(self): + data = unittest_pb2.TestAllTypes(repeated_int64=[0, 1, 2]) + self.assertEqual(2, data.repeated_int64[np.int64(-1)]) + + def testNumpyFloatScalarIndexing_Fails(self): + data = unittest_pb2.TestAllTypes(repeated_int64=[0, 1, 2]) + with self.assertRaises(TypeError): + _ = data.repeated_int64[np.float64(0.0)] + + def testNumpyIntArrayIndexing_Fails(self): + data = unittest_pb2.TestAllTypes(repeated_int64=[0, 1, 2]) + with self.assertRaises(TypeError): + _ = data.repeated_int64[np.array([0])] + with self.assertRaises(TypeError): + _ = data.repeated_int64[np.ndarray((1,), buffer=np.array([0]), dtype=int)] + with self.assertRaises(TypeError): + _ = data.repeated_int64[np.ndarray((1, 1), + buffer=np.array([0]), + dtype=int)] + +if __name__ == '__main__': + unittest.main() diff --git a/ruby/BUILD.bazel b/ruby/BUILD.bazel index d014402f45..5e15d9241a 100644 --- a/ruby/BUILD.bazel +++ b/ruby/BUILD.bazel @@ -3,6 +3,7 @@ # See also code generation logic under /src/google/protobuf/compiler/ruby. load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix") +load("@upb//cmake:build_defs.bzl", "staleness_test") load("//build_defs:internal_shell.bzl", "inline_sh_test") load("//conformance:defs.bzl", "conformance_test") load("//:protobuf.bzl", "internal_ruby_proto_library") @@ -161,6 +162,29 @@ conformance_test( }), ) +genrule( + name = "copy_ruby_amalgamation_h", + srcs = ["@upb//:ruby-upb.h"], + outs = ["generated-in/ext/google/protobuf_c/ruby-upb.h"], + cmd = "cp $< $@", +) + +genrule( + name = "copy_ruby_amalgamation_c", + srcs = ["@upb//:ruby-upb.c"], + outs = ["generated-in/ext/google/protobuf_c/ruby-upb.c"], + cmd = "cp $< $@", +) + +staleness_test( + name = "test_amalgamation_staleness", + outs = [ + "ext/google/protobuf_c/ruby-upb.h", + "ext/google/protobuf_c/ruby-upb.c", + ], + generated_pattern = "generated-in/%s", +) + ################################################################################ # Distribution files ################################################################################ diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c index 5acff8096d..629513663a 100644 --- a/ruby/ext/google/protobuf_c/message.c +++ b/ruby/ext/google/protobuf_c/message.c @@ -696,15 +696,20 @@ bool Message_Equal(const upb_Message* m1, const upb_Message* m2, if (m1 == m2) return true; size_t size1, size2; - int encode_opts = kUpb_Encode_SkipUnknown | kUpb_Encode_Deterministic; + int encode_opts = + kUpb_EncodeOption_SkipUnknown | kUpb_EncodeOption_Deterministic; upb_Arena* arena_tmp = upb_Arena_New(); const upb_MiniTable* layout = upb_MessageDef_MiniTable(m); // Compare deterministically serialized payloads with no unknown fields. - char* data1 = upb_Encode(m1, layout, encode_opts, arena_tmp, &size1); - char* data2 = upb_Encode(m2, layout, encode_opts, arena_tmp, &size2); - - if (data1 && data2) { + char* data1; + char* data2; + upb_EncodeStatus status1 = + upb_Encode(m1, layout, encode_opts, arena_tmp, &data1, &size1); + upb_EncodeStatus status2 = + upb_Encode(m2, layout, encode_opts, arena_tmp, &data2, &size2); + + if (status1 == kUpb_EncodeStatus_Ok && status2 == kUpb_EncodeStatus_Ok) { bool ret = (size1 == size2) && (memcmp(data1, data2, size1) == 0); upb_Arena_Free(arena_tmp); return ret; @@ -736,15 +741,16 @@ static VALUE Message_eq(VALUE _self, VALUE _other) { uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m, uint64_t seed) { upb_Arena* arena = upb_Arena_New(); - const char* data; + char* data; size_t size; // Hash a deterministically serialized payloads with no unknown fields. - data = upb_Encode(msg, upb_MessageDef_MiniTable(m), - kUpb_Encode_SkipUnknown | kUpb_Encode_Deterministic, arena, - &size); + upb_EncodeStatus status = upb_Encode( + msg, upb_MessageDef_MiniTable(m), + kUpb_EncodeOption_SkipUnknown | kUpb_EncodeOption_Deterministic, arena, + &data, &size); - if (data) { + if (status == kUpb_EncodeStatus_Ok) { uint64_t ret = _upb_Hash(data, size, seed); upb_Arena_Free(arena); return ret; @@ -970,7 +976,8 @@ static VALUE Message_decode(int argc, VALUE* argv, VALUE klass) { rb_raise(rb_eArgError, "Expected hash arguments."); } - VALUE depth = rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit"))); + VALUE depth = + rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit"))); if (depth != Qnil && TYPE(depth) == T_FIXNUM) { options |= UPB_DECODE_MAXDEPTH(FIX2INT(depth)); @@ -984,9 +991,10 @@ static VALUE Message_decode(int argc, VALUE* argv, VALUE klass) { VALUE msg_rb = initialize_rb_class_with_no_args(klass); Message* msg = ruby_to_Message(msg_rb); - upb_DecodeStatus status = upb_Decode( - RSTRING_PTR(data), RSTRING_LEN(data), (upb_Message*)msg->msg, - upb_MessageDef_MiniTable(msg->msgdef), NULL, options, Arena_get(msg->arena)); + upb_DecodeStatus status = + upb_Decode(RSTRING_PTR(data), RSTRING_LEN(data), (upb_Message*)msg->msg, + upb_MessageDef_MiniTable(msg->msgdef), NULL, options, + Arena_get(msg->arena)); if (status != kUpb_DecodeStatus_Ok) { rb_raise(cParseError, "Error occurred during parsing"); @@ -1070,7 +1078,7 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) { static VALUE Message_encode(int argc, VALUE* argv, VALUE klass) { Message* msg = ruby_to_Message(argv[0]); int options = 0; - const char* data; + char* data; size_t size; if (CLASS_OF(argv[0]) != klass) { @@ -1086,19 +1094,21 @@ static VALUE Message_encode(int argc, VALUE* argv, VALUE klass) { if (TYPE(hash_args) != T_HASH) { rb_raise(rb_eArgError, "Expected hash arguments."); } - VALUE depth = rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit"))); + VALUE depth = + rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit"))); if (depth != Qnil && TYPE(depth) == T_FIXNUM) { options |= UPB_DECODE_MAXDEPTH(FIX2INT(depth)); } } - upb_Arena *arena = upb_Arena_New(); + upb_Arena* arena = upb_Arena_New(); - data = upb_Encode(msg->msg, upb_MessageDef_MiniTable(msg->msgdef), - options, arena, &size); + upb_EncodeStatus status = + upb_Encode(msg->msg, upb_MessageDef_MiniTable(msg->msgdef), options, + arena, &data, &size); - if (data) { + if (status == kUpb_EncodeStatus_Ok) { VALUE ret = rb_str_new(data, size); rb_enc_associate(ret, rb_ascii8bit_encoding()); upb_Arena_Free(arena); @@ -1136,7 +1146,8 @@ static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) { if (argc == 2) { VALUE hash_args = argv[1]; if (TYPE(hash_args) != T_HASH) { - if (RTEST(rb_funcall(hash_args, rb_intern("respond_to?"), 1, rb_str_new2("to_h")))) { + if (RTEST(rb_funcall(hash_args, rb_intern("respond_to?"), 1, + rb_str_new2("to_h")))) { hash_args = rb_funcall(hash_args, rb_intern("to_h"), 0); } else { rb_raise(rb_eArgError, "Expected hash arguments."); @@ -1295,11 +1306,13 @@ upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m, const upb_MiniTable* layout = upb_MessageDef_MiniTable(m); size_t size; - char* data = upb_Encode(msg, layout, 0, tmp_arena, &size); upb_Message* new_msg = upb_Message_New(m, arena); + char* data; - if (!data || upb_Decode(data, size, new_msg, layout, NULL, 0, arena) != - kUpb_DecodeStatus_Ok) { + if (upb_Encode(msg, layout, 0, tmp_arena, &data, &size) != + kUpb_EncodeStatus_Ok || + upb_Decode(data, size, new_msg, layout, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { upb_Arena_Free(tmp_arena); rb_raise(cParseError, "Error occurred copying proto"); } @@ -1399,7 +1412,8 @@ static void Message_define_class(VALUE klass) { void Message_register(VALUE protobuf) { cParseError = rb_const_get(protobuf, rb_intern("ParseError")); - cAbstractMessage = rb_define_class_under(protobuf, "AbstractMessage", rb_cObject); + cAbstractMessage = + rb_define_class_under(protobuf, "AbstractMessage", rb_cObject); Message_define_class(cAbstractMessage); rb_gc_register_address(&cAbstractMessage); diff --git a/ruby/ext/google/protobuf_c/ruby-upb.c b/ruby/ext/google/protobuf_c/ruby-upb.c old mode 100755 new mode 100644 index d50bd99f9c..7a7a7ad4b7 --- a/ruby/ext/google/protobuf_c/ruby-upb.c +++ b/ruby/ext/google/protobuf_c/ruby-upb.c @@ -1,31 +1,5 @@ /* Amalgamated source file */ #include "ruby-upb.h" -/* - * Copyright (c) 2009-2021, Google LLC - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Google LLC nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ /* * This is where we define macros used across upb. @@ -56,8 +30,20 @@ #error upb requires C99 or C++11 or MSVC >= 2015. #endif -#include +// Portable check for GCC minimum version: +// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +#define UPB_GNUC_MIN(x, y) \ + (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y)) +#else +#define UPB_GNUC_MIN(x, y) 0 +#endif + +#include +#include +#include #include +#include #if UINTPTR_MAX == 0xffffffff #define UPB_SIZE(size32, size64) size32 @@ -90,9 +76,10 @@ #define UPB_INLINE static #endif +#define UPB_MALLOC_ALIGN 8 #define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align)) #define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align)) -#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, 16) +#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, UPB_MALLOC_ALIGN) #define UPB_ALIGN_OF(type) offsetof (struct { char c; type member; }, member) /* Hints to the compiler about likely/unlikely branches. */ @@ -230,7 +217,11 @@ #undef UPB_FASTTABLE_SUPPORTED -/* ASAN poisoning (for arena) *************************************************/ +/* ASAN poisoning (for arena). + * If using UPB from an interpreted language like Ruby, a build of the + * interpreter compiled with ASAN enabled must be used in order to get sane and + * expected behavior. + */ #if defined(__SANITIZE_ADDRESS__) #define UPB_ASAN 1 @@ -262,5275 +253,6108 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); #define UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 0 #endif -/** upb/decode.c ************************************************************/ - -#include -#include +#if defined(__cplusplus) +#if defined(__clang__) || UPB_GNUC_MIN(6, 0) +// https://gcc.gnu.org/gcc-6/changes.html +#if __cplusplus >= 201402L +#define UPB_DEPRECATED [[deprecated]] +#else +#define UPB_DEPRECATED __attribute__((deprecated)) +#endif +#else +#define UPB_DEPRECATED +#endif +#else +#define UPB_DEPRECATED +#endif -/* Must be last. */ - -/* Maps descriptor type -> elem_size_lg2. */ -static const uint8_t desctype_to_elem_size_lg2[] = { - -1, /* invalid descriptor type */ - 3, /* DOUBLE */ - 2, /* FLOAT */ - 3, /* INT64 */ - 3, /* UINT64 */ - 2, /* INT32 */ - 3, /* FIXED64 */ - 2, /* FIXED32 */ - 0, /* BOOL */ - UPB_SIZE(3, 4), /* STRING */ - UPB_SIZE(2, 3), /* GROUP */ - UPB_SIZE(2, 3), /* MESSAGE */ - UPB_SIZE(3, 4), /* BYTES */ - 2, /* UINT32 */ - 2, /* ENUM */ - 2, /* SFIXED32 */ - 3, /* SFIXED64 */ - 2, /* SINT32 */ - 3, /* SINT64 */ -}; +#include -/* Maps descriptor type -> upb map size. */ -static const uint8_t desctype_to_mapsize[] = { - -1, /* invalid descriptor type */ - 8, /* DOUBLE */ - 4, /* FLOAT */ - 8, /* INT64 */ - 8, /* UINT64 */ - 4, /* INT32 */ - 8, /* FIXED64 */ - 4, /* FIXED32 */ - 1, /* BOOL */ - UPB_MAPTYPE_STRING, /* STRING */ - sizeof(void*), /* GROUP */ - sizeof(void*), /* MESSAGE */ - UPB_MAPTYPE_STRING, /* BYTES */ - 4, /* UINT32 */ - 4, /* ENUM */ - 4, /* SFIXED32 */ - 8, /* SFIXED64 */ - 4, /* SINT32 */ - 8, /* SINT64 */ -}; +// Must be last. -static const unsigned FIXED32_OK_MASK = (1 << kUpb_FieldType_Float) | - (1 << kUpb_FieldType_Fixed32) | - (1 << kUpb_FieldType_SFixed32); - -static const unsigned FIXED64_OK_MASK = (1 << kUpb_FieldType_Double) | - (1 << kUpb_FieldType_Fixed64) | - (1 << kUpb_FieldType_SFixed64); - -/* Three fake field types for MessageSet. */ -#define TYPE_MSGSET_ITEM 19 -#define TYPE_MSGSET_TYPE_ID 20 -#define TYPE_COUNT 20 - -/* Op: an action to be performed for a wire-type/field-type combination. */ -#define OP_UNKNOWN -1 /* Unknown field. */ -#define OP_MSGSET_ITEM -2 -#define OP_MSGSET_TYPEID -3 -#define OP_SCALAR_LG2(n) (n) /* n in [0, 2, 3] => op in [0, 2, 3] */ -#define OP_ENUM 1 -#define OP_STRING 4 -#define OP_BYTES 5 -#define OP_SUBMSG 6 -/* Scalar fields use only ops above. Repeated fields can use any op. */ -#define OP_FIXPCK_LG2(n) (n + 5) /* n in [2, 3] => op in [7, 8] */ -#define OP_VARPCK_LG2(n) (n + 9) /* n in [0, 2, 3] => op in [9, 11, 12] */ -#define OP_PACKED_ENUM 13 - -static const int8_t varint_ops[] = { - OP_UNKNOWN, /* field not found */ - OP_UNKNOWN, /* DOUBLE */ - OP_UNKNOWN, /* FLOAT */ - OP_SCALAR_LG2(3), /* INT64 */ - OP_SCALAR_LG2(3), /* UINT64 */ - OP_SCALAR_LG2(2), /* INT32 */ - OP_UNKNOWN, /* FIXED64 */ - OP_UNKNOWN, /* FIXED32 */ - OP_SCALAR_LG2(0), /* BOOL */ - OP_UNKNOWN, /* STRING */ - OP_UNKNOWN, /* GROUP */ - OP_UNKNOWN, /* MESSAGE */ - OP_UNKNOWN, /* BYTES */ - OP_SCALAR_LG2(2), /* UINT32 */ - OP_ENUM, /* ENUM */ - OP_UNKNOWN, /* SFIXED32 */ - OP_UNKNOWN, /* SFIXED64 */ - OP_SCALAR_LG2(2), /* SINT32 */ - OP_SCALAR_LG2(3), /* SINT64 */ - OP_UNKNOWN, /* MSGSET_ITEM */ - OP_MSGSET_TYPEID, /* MSGSET TYPEID */ -}; +bool _upb_array_realloc(upb_Array* arr, size_t min_capacity, upb_Arena* arena) { + size_t new_capacity = UPB_MAX(arr->capacity, 4); + int elem_size_lg2 = arr->data & 7; + size_t old_bytes = arr->capacity << elem_size_lg2; + size_t new_bytes; + void* ptr = _upb_array_ptr(arr); -static const int8_t delim_ops[] = { - /* For non-repeated field type. */ - OP_UNKNOWN, /* field not found */ - OP_UNKNOWN, /* DOUBLE */ - OP_UNKNOWN, /* FLOAT */ - OP_UNKNOWN, /* INT64 */ - OP_UNKNOWN, /* UINT64 */ - OP_UNKNOWN, /* INT32 */ - OP_UNKNOWN, /* FIXED64 */ - OP_UNKNOWN, /* FIXED32 */ - OP_UNKNOWN, /* BOOL */ - OP_STRING, /* STRING */ - OP_UNKNOWN, /* GROUP */ - OP_SUBMSG, /* MESSAGE */ - OP_BYTES, /* BYTES */ - OP_UNKNOWN, /* UINT32 */ - OP_UNKNOWN, /* ENUM */ - OP_UNKNOWN, /* SFIXED32 */ - OP_UNKNOWN, /* SFIXED64 */ - OP_UNKNOWN, /* SINT32 */ - OP_UNKNOWN, /* SINT64 */ - OP_UNKNOWN, /* MSGSET_ITEM */ - OP_UNKNOWN, /* MSGSET TYPEID */ - /* For repeated field type. */ - OP_FIXPCK_LG2(3), /* REPEATED DOUBLE */ - OP_FIXPCK_LG2(2), /* REPEATED FLOAT */ - OP_VARPCK_LG2(3), /* REPEATED INT64 */ - OP_VARPCK_LG2(3), /* REPEATED UINT64 */ - OP_VARPCK_LG2(2), /* REPEATED INT32 */ - OP_FIXPCK_LG2(3), /* REPEATED FIXED64 */ - OP_FIXPCK_LG2(2), /* REPEATED FIXED32 */ - OP_VARPCK_LG2(0), /* REPEATED BOOL */ - OP_STRING, /* REPEATED STRING */ - OP_SUBMSG, /* REPEATED GROUP */ - OP_SUBMSG, /* REPEATED MESSAGE */ - OP_BYTES, /* REPEATED BYTES */ - OP_VARPCK_LG2(2), /* REPEATED UINT32 */ - OP_PACKED_ENUM, /* REPEATED ENUM */ - OP_FIXPCK_LG2(2), /* REPEATED SFIXED32 */ - OP_FIXPCK_LG2(3), /* REPEATED SFIXED64 */ - OP_VARPCK_LG2(2), /* REPEATED SINT32 */ - OP_VARPCK_LG2(3), /* REPEATED SINT64 */ - /* Omitting MSGSET_*, because we never emit a repeated msgset type */ -}; + /* Log2 ceiling of size. */ + while (new_capacity < min_capacity) new_capacity *= 2; -typedef union { - bool bool_val; - uint32_t uint32_val; - uint64_t uint64_val; - uint32_t size; -} wireval; + new_bytes = new_capacity << elem_size_lg2; + ptr = upb_Arena_Realloc(arena, ptr, old_bytes, new_bytes); -static const char* decode_msg(upb_Decoder* d, const char* ptr, upb_Message* msg, - const upb_MiniTable* layout); + if (!ptr) { + return false; + } -UPB_NORETURN static void* decode_err(upb_Decoder* d, upb_DecodeStatus status) { - assert(status != kUpb_DecodeStatus_Ok); - UPB_LONGJMP(d->err, status); + arr->data = _upb_tag_arrptr(ptr, elem_size_lg2); + arr->capacity = new_capacity; + return true; } -const char* fastdecode_err(upb_Decoder* d, int status) { - assert(status != kUpb_DecodeStatus_Ok); - UPB_LONGJMP(d->err, status); - return NULL; -} -static void decode_verifyutf8(upb_Decoder* d, const char* buf, int len) { - if (!decode_verifyutf8_inl(buf, len)) - decode_err(d, kUpb_DecodeStatus_BadUtf8); +static upb_Array* getorcreate_array(upb_Array** arr_ptr, int elem_size_lg2, + upb_Arena* arena) { + upb_Array* arr = *arr_ptr; + if (!arr) { + arr = _upb_Array_New(arena, 4, elem_size_lg2); + if (!arr) return NULL; + *arr_ptr = arr; + } + return arr; } -static bool decode_reserve(upb_Decoder* d, upb_Array* arr, size_t elem) { - bool need_realloc = arr->size - arr->len < elem; - if (need_realloc && !_upb_array_realloc(arr, arr->len + elem, &d->arena)) { - decode_err(d, kUpb_DecodeStatus_OutOfMemory); - } - return need_realloc; +void* _upb_Array_Resize_fallback(upb_Array** arr_ptr, size_t size, + int elem_size_lg2, upb_Arena* arena) { + upb_Array* arr = getorcreate_array(arr_ptr, elem_size_lg2, arena); + return arr && _upb_Array_Resize(arr, size, arena) ? _upb_array_ptr(arr) + : NULL; } -typedef struct { - const char* ptr; - uint64_t val; -} decode_vret; +bool _upb_Array_Append_fallback(upb_Array** arr_ptr, const void* value, + int elem_size_lg2, upb_Arena* arena) { + upb_Array* arr = getorcreate_array(arr_ptr, elem_size_lg2, arena); + if (!arr) return false; -UPB_NOINLINE -static decode_vret decode_longvarint64(const char* ptr, uint64_t val) { - decode_vret ret = {NULL, 0}; - uint64_t byte; - int i; - for (i = 1; i < 10; i++) { - byte = (uint8_t)ptr[i]; - val += (byte - 1) << (i * 7); - if (!(byte & 0x80)) { - ret.ptr = ptr + i + 1; - ret.val = val; - return ret; - } - } - return ret; -} + size_t elems = arr->size; -UPB_FORCEINLINE -static const char* decode_varint64(upb_Decoder* d, const char* ptr, - uint64_t* val) { - uint64_t byte = (uint8_t)*ptr; - if (UPB_LIKELY((byte & 0x80) == 0)) { - *val = byte; - return ptr + 1; - } else { - decode_vret res = decode_longvarint64(ptr, byte); - if (!res.ptr) return decode_err(d, kUpb_DecodeStatus_Malformed); - *val = res.val; - return res.ptr; + if (!_upb_Array_Resize(arr, elems + 1, arena)) { + return false; } -} -UPB_FORCEINLINE -static const char* decode_tag(upb_Decoder* d, const char* ptr, uint32_t* val) { - uint64_t byte = (uint8_t)*ptr; - if (UPB_LIKELY((byte & 0x80) == 0)) { - *val = byte; - return ptr + 1; - } else { - const char* start = ptr; - decode_vret res = decode_longvarint64(ptr, byte); - if (!res.ptr || res.ptr - start > 5 || res.val > UINT32_MAX) { - return decode_err(d, kUpb_DecodeStatus_Malformed); - } - *val = res.val; - return res.ptr; - } + char* data = _upb_array_ptr(arr); + memcpy(data + (elems << elem_size_lg2), value, 1 << elem_size_lg2); + return true; } -static void decode_munge_int32(wireval* val) { - if (!_upb_IsLittleEndian()) { - /* The next stage will memcpy(dst, &val, 4) */ - val->uint32_val = val->uint64_val; - } -} -static void decode_munge(int type, wireval* val) { - switch (type) { - case kUpb_FieldType_Bool: - val->bool_val = val->uint64_val != 0; - break; - case kUpb_FieldType_SInt32: { - uint32_t n = val->uint64_val; - val->uint32_val = (n >> 1) ^ -(int32_t)(n & 1); - break; - } - case kUpb_FieldType_SInt64: { - uint64_t n = val->uint64_val; - val->uint64_val = (n >> 1) ^ -(int64_t)(n & 1); - break; +// Must be last. + +const char* upb_BufToUint64(const char* ptr, const char* end, uint64_t* val) { + uint64_t u64 = 0; + while (ptr < end) { + unsigned ch = *ptr - '0'; + if (ch >= 10) break; + if (u64 > UINT64_MAX / 10 || u64 * 10 > UINT64_MAX - ch) { + return NULL; // integer overflow } - case kUpb_FieldType_Int32: - case kUpb_FieldType_UInt32: - case kUpb_FieldType_Enum: - decode_munge_int32(val); - break; + u64 *= 10; + u64 += ch; + ptr++; } -} -static upb_Message* decode_newsubmsg(upb_Decoder* d, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field) { - const upb_MiniTable* subl = subs[field->submsg_index].submsg; - return _upb_Message_New_inl(subl, &d->arena); + *val = u64; + return ptr; } -UPB_NOINLINE -const char* decode_isdonefallback(upb_Decoder* d, const char* ptr, - int overrun) { - int status; - ptr = decode_isdonefallback_inl(d, ptr, overrun, &status); - if (ptr == NULL) { - return decode_err(d, status); +const char* upb_BufToInt64(const char* ptr, const char* end, int64_t* val, + bool* is_neg) { + bool neg = false; + uint64_t u64; + + if (ptr != end && *ptr == '-') { + ptr++; + neg = true; } - return ptr; -} -static const char* decode_readstr(upb_Decoder* d, const char* ptr, int size, - upb_StringView* str) { - if (d->options & kUpb_DecodeOption_AliasString) { - str->data = ptr; - } else { - char* data = upb_Arena_Malloc(&d->arena, size); - if (!data) return decode_err(d, kUpb_DecodeStatus_OutOfMemory); - memcpy(data, ptr, size); - str->data = data; + ptr = upb_BufToUint64(ptr, end, &u64); + if (!ptr || u64 > (uint64_t)INT64_MAX + neg) { + return NULL; // integer overflow } - str->size = size; - return ptr + size; -} -UPB_FORCEINLINE -static const char* decode_tosubmsg2(upb_Decoder* d, const char* ptr, - upb_Message* submsg, - const upb_MiniTable* subl, int size) { - int saved_delta = decode_pushlimit(d, ptr, size); - if (--d->depth < 0) return decode_err(d, kUpb_DecodeStatus_MaxDepthExceeded); - ptr = decode_msg(d, ptr, submsg, subl); - if (d->end_group != DECODE_NOGROUP) - return decode_err(d, kUpb_DecodeStatus_Malformed); - decode_poplimit(d, ptr, saved_delta); - d->depth++; + *val = neg ? -u64 : u64; + if (is_neg) *is_neg = neg; return ptr; } -UPB_FORCEINLINE -static const char* decode_tosubmsg(upb_Decoder* d, const char* ptr, - upb_Message* submsg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, int size) { - return decode_tosubmsg2(d, ptr, submsg, subs[field->submsg_index].submsg, - size); -} -UPB_FORCEINLINE -static const char* decode_group(upb_Decoder* d, const char* ptr, - upb_Message* submsg, const upb_MiniTable* subl, - uint32_t number) { - if (--d->depth < 0) return decode_err(d, kUpb_DecodeStatus_MaxDepthExceeded); - if (decode_isdone(d, &ptr)) { - return decode_err(d, kUpb_DecodeStatus_Malformed); - } - ptr = decode_msg(d, ptr, submsg, subl); - if (d->end_group != number) return decode_err(d, kUpb_DecodeStatus_Malformed); - d->end_group = DECODE_NOGROUP; - d->depth++; - return ptr; -} +#include -UPB_FORCEINLINE -static const char* decode_togroup(upb_Decoder* d, const char* ptr, - upb_Message* submsg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field) { - const upb_MiniTable* subl = subs[field->submsg_index].submsg; - return decode_group(d, ptr, submsg, subl, field->number); -} -static char* encode_varint32(uint32_t val, char* ptr) { - do { - uint8_t byte = val & 0x7fU; - val >>= 7; - if (val) byte |= 0x80U; - *(ptr++) = byte; - } while (val); - return ptr; +// Must be last. + +/* Strings/bytes are special-cased in maps. */ +static char _upb_CTypeo_mapsize[12] = { + 0, + 1, /* kUpb_CType_Bool */ + 4, /* kUpb_CType_Float */ + 4, /* kUpb_CType_Int32 */ + 4, /* kUpb_CType_UInt32 */ + 4, /* kUpb_CType_Enum */ + sizeof(void*), /* kUpb_CType_Message */ + 8, /* kUpb_CType_Double */ + 8, /* kUpb_CType_Int64 */ + 8, /* kUpb_CType_UInt64 */ + 0, /* kUpb_CType_String */ + 0, /* kUpb_CType_Bytes */ +}; + +upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type) { + return _upb_Map_New(a, _upb_CTypeo_mapsize[key_type], + _upb_CTypeo_mapsize[value_type]); } -static void upb_Decode_AddUnknownVarints(upb_Decoder* d, upb_Message* msg, - uint32_t val1, uint32_t val2) { - char buf[20]; - char* end = buf; - end = encode_varint32(val1, end); - end = encode_varint32(val2, end); +size_t upb_Map_Size(const upb_Map* map) { return _upb_Map_Size(map); } - if (!_upb_Message_AddUnknown(msg, buf, end - buf, &d->arena)) { - decode_err(d, kUpb_DecodeStatus_OutOfMemory); - } +bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, + upb_MessageValue* val) { + return _upb_Map_Get(map, &key, map->key_size, val, map->val_size); } -UPB_NOINLINE -static bool decode_checkenum_slow(upb_Decoder* d, const char* ptr, - upb_Message* msg, const upb_MiniTable_Enum* e, - const upb_MiniTable_Field* field, - uint32_t v) { - // OPT: binary search long lists? - int n = e->value_count; - for (int i = 0; i < n; i++) { - if ((uint32_t)e->values[i] == v) return true; - } +void upb_Map_Clear(upb_Map* map) { _upb_Map_Clear(map); } - // Unrecognized enum goes into unknown fields. - // For packed fields the tag could be arbitrarily far in the past, so we - // just re-encode the tag and value here. - uint32_t tag = ((uint32_t)field->number << 3) | kUpb_WireType_Varint; - upb_Decode_AddUnknownVarints(d, msg, tag, v); - return false; +upb_MapInsertStatus upb_Map_Insert(upb_Map* map, upb_MessageValue key, + upb_MessageValue val, upb_Arena* arena) { + return (upb_MapInsertStatus)_upb_Map_Insert(map, &key, map->key_size, &val, + map->val_size, arena); } -UPB_FORCEINLINE -static bool decode_checkenum(upb_Decoder* d, const char* ptr, upb_Message* msg, - const upb_MiniTable_Enum* e, - const upb_MiniTable_Field* field, wireval* val) { - uint32_t v = val->uint32_val; +bool upb_Map_Delete(upb_Map* map, upb_MessageValue key) { + return _upb_Map_Delete(map, &key, map->key_size); +} - if (UPB_LIKELY(v < 64) && UPB_LIKELY(((1ULL << v) & e->mask))) return true; +bool upb_MapIterator_Next(const upb_Map* map, size_t* iter) { + return _upb_map_next(map, iter); +} - return decode_checkenum_slow(d, ptr, msg, e, field, v); +bool upb_MapIterator_Done(const upb_Map* map, size_t iter) { + upb_strtable_iter i; + UPB_ASSERT(iter != kUpb_Map_Begin); + i.t = &map->table; + i.index = iter; + return upb_strtable_done(&i); } -UPB_NOINLINE -static const char* decode_enum_toarray(upb_Decoder* d, const char* ptr, - upb_Message* msg, upb_Array* arr, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, - wireval* val) { - const upb_MiniTable_Enum* e = subs[field->submsg_index].subenum; - if (!decode_checkenum(d, ptr, msg, e, field, val)) return ptr; - void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void); - arr->len++; - memcpy(mem, val, 4); - return ptr; +/* Returns the key and value for this entry of the map. */ +upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter) { + upb_strtable_iter i; + upb_MessageValue ret; + i.t = &map->table; + i.index = iter; + _upb_map_fromkey(upb_strtable_iter_key(&i), &ret, map->key_size); + return ret; } -UPB_FORCEINLINE -static const char* decode_fixed_packed(upb_Decoder* d, const char* ptr, - upb_Array* arr, wireval* val, - const upb_MiniTable_Field* field, - int lg2) { - int mask = (1 << lg2) - 1; - size_t count = val->size >> lg2; - if ((val->size & mask) != 0) { - // Length isn't a round multiple of elem size. - return decode_err(d, kUpb_DecodeStatus_Malformed); - } - decode_reserve(d, arr, count); - void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); - arr->len += count; - // Note: if/when the decoder supports multi-buffer input, we will need to - // handle buffer seams here. - if (_upb_IsLittleEndian()) { - memcpy(mem, ptr, val->size); - ptr += val->size; - } else { - const char* end = ptr + val->size; - char* dst = mem; - while (ptr < end) { - if (lg2 == 2) { - uint32_t val; - memcpy(&val, ptr, sizeof(val)); - val = _upb_BigEndian_Swap32(val); - memcpy(dst, &val, sizeof(val)); - } else { - UPB_ASSERT(lg2 == 3); - uint64_t val; - memcpy(&val, ptr, sizeof(val)); - val = _upb_BigEndian_Swap64(val); - memcpy(dst, &val, sizeof(val)); - } - ptr += 1 << lg2; - dst += 1 << lg2; - } - } - - return ptr; +upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter) { + upb_strtable_iter i; + upb_MessageValue ret; + i.t = &map->table; + i.index = iter; + _upb_map_fromvalue(upb_strtable_iter_value(&i), &ret, map->val_size); + return ret; } -UPB_FORCEINLINE -static const char* decode_varint_packed(upb_Decoder* d, const char* ptr, - upb_Array* arr, wireval* val, - const upb_MiniTable_Field* field, - int lg2) { - int scale = 1 << lg2; - int saved_limit = decode_pushlimit(d, ptr, val->size); - char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); - while (!decode_isdone(d, &ptr)) { - wireval elem; - ptr = decode_varint64(d, ptr, &elem.uint64_val); - decode_munge(field->descriptortype, &elem); - if (decode_reserve(d, arr, 1)) { - out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); - } - arr->len++; - memcpy(out, &elem, scale); - out += scale; - } - decode_poplimit(d, ptr, saved_limit); - return ptr; -} +/* void upb_MapIterator_SetValue(upb_Map *map, size_t iter, upb_MessageValue + * value); */ +/* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/descriptor.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ -UPB_NOINLINE -static const char* decode_enum_packed(upb_Decoder* d, const char* ptr, - upb_Message* msg, upb_Array* arr, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, - wireval* val) { - const upb_MiniTable_Enum* e = subs[field->submsg_index].subenum; - int saved_limit = decode_pushlimit(d, ptr, val->size); - char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void); - while (!decode_isdone(d, &ptr)) { - wireval elem; - ptr = decode_varint64(d, ptr, &elem.uint64_val); - decode_munge_int32(&elem); - if (!decode_checkenum(d, ptr, msg, e, field, &elem)) { - continue; - } - if (decode_reserve(d, arr, 1)) { - out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void); - } - arr->len++; - memcpy(out, &elem, 4); - out += 4; - } - decode_poplimit(d, ptr, saved_limit); - return ptr; -} +#include -static const char* decode_toarray(upb_Decoder* d, const char* ptr, - upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, - wireval* val, int op) { - upb_Array** arrp = UPB_PTR_AT(msg, field->offset, void); - upb_Array* arr = *arrp; - void* mem; - if (arr) { - decode_reserve(d, arr, 1); - } else { - size_t lg2 = desctype_to_elem_size_lg2[field->descriptortype]; - arr = _upb_Array_New(&d->arena, 4, lg2); - if (!arr) return decode_err(d, kUpb_DecodeStatus_OutOfMemory); - *arrp = arr; - } +static const upb_MiniTable_Sub google_protobuf_FileDescriptorSet_submsgs[1] = { + {.submsg = &google_protobuf_FileDescriptorProto_msg_init}, +}; - switch (op) { - case OP_SCALAR_LG2(0): - case OP_SCALAR_LG2(2): - case OP_SCALAR_LG2(3): - /* Append scalar value. */ - mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << op, void); - arr->len++; - memcpy(mem, val, 1 << op); - return ptr; - case OP_STRING: - decode_verifyutf8(d, ptr, val->size); - /* Fallthrough. */ - case OP_BYTES: { - /* Append bytes. */ - upb_StringView* str = (upb_StringView*)_upb_array_ptr(arr) + arr->len; - arr->len++; - return decode_readstr(d, ptr, val->size, str); - } - case OP_SUBMSG: { - /* Append submessage / group. */ - upb_Message* submsg = decode_newsubmsg(d, subs, field); - *UPB_PTR_AT(_upb_array_ptr(arr), arr->len * sizeof(void*), upb_Message*) = - submsg; - arr->len++; - if (UPB_UNLIKELY(field->descriptortype == kUpb_FieldType_Group)) { - return decode_togroup(d, ptr, submsg, subs, field); - } else { - return decode_tosubmsg(d, ptr, submsg, subs, field, val->size); - } - } - case OP_FIXPCK_LG2(2): - case OP_FIXPCK_LG2(3): - return decode_fixed_packed(d, ptr, arr, val, field, - op - OP_FIXPCK_LG2(0)); - case OP_VARPCK_LG2(0): - case OP_VARPCK_LG2(2): - case OP_VARPCK_LG2(3): - return decode_varint_packed(d, ptr, arr, val, field, - op - OP_VARPCK_LG2(0)); - case OP_ENUM: - return decode_enum_toarray(d, ptr, msg, arr, subs, field, val); - case OP_PACKED_ENUM: - return decode_enum_packed(d, ptr, msg, arr, subs, field, val); - default: - UPB_UNREACHABLE(); - } -} +static const upb_MiniTable_Field google_protobuf_FileDescriptorSet__fields[1] = { + {1, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -static const char* decode_tomap(upb_Decoder* d, const char* ptr, - upb_Message* msg, const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, - wireval* val) { - upb_Map** map_p = UPB_PTR_AT(msg, field->offset, upb_Map*); - upb_Map* map = *map_p; - upb_MapEntry ent; - const upb_MiniTable* entry = subs[field->submsg_index].submsg; +const upb_MiniTable google_protobuf_FileDescriptorSet_msg_init = { + &google_protobuf_FileDescriptorSet_submsgs[0], + &google_protobuf_FileDescriptorSet__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, +}; - if (!map) { - /* Lazily create map. */ - const upb_MiniTable_Field* key_field = &entry->fields[0]; - const upb_MiniTable_Field* val_field = &entry->fields[1]; - char key_size = desctype_to_mapsize[key_field->descriptortype]; - char val_size = desctype_to_mapsize[val_field->descriptortype]; - UPB_ASSERT(key_field->offset == 0); - UPB_ASSERT(val_field->offset == sizeof(upb_StringView)); - map = _upb_Map_New(&d->arena, key_size, val_size); - *map_p = map; - } +static const upb_MiniTable_Sub google_protobuf_FileDescriptorProto_submsgs[6] = { + {.submsg = &google_protobuf_DescriptorProto_msg_init}, + {.submsg = &google_protobuf_EnumDescriptorProto_msg_init}, + {.submsg = &google_protobuf_ServiceDescriptorProto_msg_init}, + {.submsg = &google_protobuf_FieldDescriptorProto_msg_init}, + {.submsg = &google_protobuf_FileOptions_msg_init}, + {.submsg = &google_protobuf_SourceCodeInfo_msg_init}, +}; - /* Parse map entry. */ - memset(&ent, 0, sizeof(ent)); +static const upb_MiniTable_Field google_protobuf_FileDescriptorProto__fields[13] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(20, 40), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(24, 48), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(28, 56), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(32, 64), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(36, 72), UPB_SIZE(0, 0), 3, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(40, 80), UPB_SIZE(3, 3), 4, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(44, 88), UPB_SIZE(4, 4), 5, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(48, 96), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {11, UPB_SIZE(52, 104), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {12, UPB_SIZE(56, 112), UPB_SIZE(5, 5), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {13, UPB_SIZE(64, 128), UPB_SIZE(6, 6), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, +}; - if (entry->fields[1].descriptortype == kUpb_FieldType_Message || - entry->fields[1].descriptortype == kUpb_FieldType_Group) { - /* Create proactively to handle the case where it doesn't appear. */ - ent.v.val = - upb_value_ptr(_upb_Message_New(entry->subs[0].submsg, &d->arena)); - } +const upb_MiniTable google_protobuf_FileDescriptorProto_msg_init = { + &google_protobuf_FileDescriptorProto_submsgs[0], + &google_protobuf_FileDescriptorProto__fields[0], + UPB_SIZE(72, 144), 13, kUpb_ExtMode_NonExtendable, 13, 255, 0, +}; - const char* start = ptr; - ptr = decode_tosubmsg(d, ptr, &ent.k, subs, field, val->size); - // check if ent had any unknown fields - size_t size; - upb_Message_GetUnknown(&ent.k, &size); - if (size != 0) { - uint32_t tag = ((uint32_t)field->number << 3) | kUpb_WireType_Delimited; - upb_Decode_AddUnknownVarints(d, msg, tag, (uint32_t)(ptr - start)); - if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { - decode_err(d, kUpb_DecodeStatus_OutOfMemory); - } - } else { - _upb_Map_Set(map, &ent.k, map->key_size, &ent.v, map->val_size, &d->arena); - } - return ptr; -} +static const upb_MiniTable_Sub google_protobuf_DescriptorProto_submsgs[8] = { + {.submsg = &google_protobuf_FieldDescriptorProto_msg_init}, + {.submsg = &google_protobuf_DescriptorProto_msg_init}, + {.submsg = &google_protobuf_EnumDescriptorProto_msg_init}, + {.submsg = &google_protobuf_DescriptorProto_ExtensionRange_msg_init}, + {.submsg = &google_protobuf_FieldDescriptorProto_msg_init}, + {.submsg = &google_protobuf_MessageOptions_msg_init}, + {.submsg = &google_protobuf_OneofDescriptorProto_msg_init}, + {.submsg = &google_protobuf_DescriptorProto_ReservedRange_msg_init}, +}; -static const char* decode_tomsg(upb_Decoder* d, const char* ptr, - upb_Message* msg, const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, wireval* val, - int op) { - void* mem = UPB_PTR_AT(msg, field->offset, void); - int type = field->descriptortype; +static const upb_MiniTable_Field google_protobuf_DescriptorProto__fields[10] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 32), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 40), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(24, 48), UPB_SIZE(0, 0), 3, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(28, 56), UPB_SIZE(0, 0), 4, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(32, 64), UPB_SIZE(2, 2), 5, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(36, 72), UPB_SIZE(0, 0), 6, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(40, 80), UPB_SIZE(0, 0), 7, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(44, 88), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - if (UPB_UNLIKELY(op == OP_ENUM) && - !decode_checkenum(d, ptr, msg, subs[field->submsg_index].subenum, field, - val)) { - return ptr; - } +const upb_MiniTable google_protobuf_DescriptorProto_msg_init = { + &google_protobuf_DescriptorProto_submsgs[0], + &google_protobuf_DescriptorProto__fields[0], + UPB_SIZE(48, 96), 10, kUpb_ExtMode_NonExtendable, 10, 255, 0, +}; - /* Set presence if necessary. */ - if (field->presence > 0) { - _upb_sethas_field(msg, field); - } else if (field->presence < 0) { - /* Oneof case */ - uint32_t* oneof_case = _upb_oneofcase_field(msg, field); - if (op == OP_SUBMSG && *oneof_case != field->number) { - memset(mem, 0, sizeof(void*)); - } - *oneof_case = field->number; - } +static const upb_MiniTable_Sub google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = { + {.submsg = &google_protobuf_ExtensionRangeOptions_msg_init}, +}; - /* Store into message. */ - switch (op) { - case OP_SUBMSG: { - upb_Message** submsgp = mem; - upb_Message* submsg = *submsgp; - if (!submsg) { - submsg = decode_newsubmsg(d, subs, field); - *submsgp = submsg; - } - if (UPB_UNLIKELY(type == kUpb_FieldType_Group)) { - ptr = decode_togroup(d, ptr, submsg, subs, field); - } else { - ptr = decode_tosubmsg(d, ptr, submsg, subs, field, val->size); - } - break; - } - case OP_STRING: - decode_verifyutf8(d, ptr, val->size); - /* Fallthrough. */ - case OP_BYTES: - return decode_readstr(d, ptr, val->size, mem); - case OP_SCALAR_LG2(3): - memcpy(mem, val, 8); - break; - case OP_ENUM: - case OP_SCALAR_LG2(2): - memcpy(mem, val, 4); - break; - case OP_SCALAR_LG2(0): - memcpy(mem, val, 1); - break; - default: - UPB_UNREACHABLE(); - } +static const upb_MiniTable_Field google_protobuf_DescriptorProto_ExtensionRange__fields[3] = { + {1, UPB_SIZE(4, 4), UPB_SIZE(1, 1), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 8), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(12, 16), UPB_SIZE(3, 3), 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - return ptr; -} +const upb_MiniTable google_protobuf_DescriptorProto_ExtensionRange_msg_init = { + &google_protobuf_DescriptorProto_ExtensionRange_submsgs[0], + &google_protobuf_DescriptorProto_ExtensionRange__fields[0], + UPB_SIZE(16, 24), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, +}; -UPB_NOINLINE -const char* decode_checkrequired(upb_Decoder* d, const char* ptr, - const upb_Message* msg, - const upb_MiniTable* l) { - assert(l->required_count); - if (UPB_LIKELY((d->options & kUpb_DecodeOption_CheckRequired) == 0)) { - return ptr; - } - uint64_t msg_head; - memcpy(&msg_head, msg, 8); - msg_head = _upb_BigEndian_Swap64(msg_head); - if (upb_MiniTable_requiredmask(l) & ~msg_head) { - d->missing_required = true; - } - return ptr; -} +static const upb_MiniTable_Field google_protobuf_DescriptorProto_ReservedRange__fields[2] = { + {1, UPB_SIZE(4, 4), UPB_SIZE(1, 1), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 8), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; -UPB_FORCEINLINE -static bool decode_tryfastdispatch(upb_Decoder* d, const char** ptr, - upb_Message* msg, - const upb_MiniTable* layout) { -#if UPB_FASTTABLE - if (layout && layout->table_mask != (unsigned char)-1) { - uint16_t tag = fastdecode_loadtag(*ptr); - intptr_t table = decode_totable(layout); - *ptr = fastdecode_tagdispatch(d, *ptr, msg, table, 0, tag); - return true; - } -#endif - return false; -} +const upb_MiniTable google_protobuf_DescriptorProto_ReservedRange_msg_init = { + NULL, + &google_protobuf_DescriptorProto_ReservedRange__fields[0], + UPB_SIZE(16, 16), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, +}; -static const char* decode_msgset(upb_Decoder* d, const char* ptr, - upb_Message* msg, - const upb_MiniTable* layout) { - // We create a temporary upb_MiniTable here and abuse its fields as temporary - // storage, to avoid creating lots of MessageSet-specific parsing code-paths: - // 1. We store 'layout' in item_layout.subs. We will need this later as - // a key to look up extensions for this MessageSet. - // 2. We use item_layout.fields as temporary storage to store the extension - // we - // found when parsing the type id. - upb_MiniTable item_layout = { - .subs = (const upb_MiniTable_Sub[]){{.submsg = layout}}, - .fields = NULL, - .size = 0, - .field_count = 0, - .ext = kUpb_ExtMode_IsMessageSet_ITEM, - .dense_below = 0, - .table_mask = -1}; - return decode_group(d, ptr, msg, &item_layout, 1); -} - -static const upb_MiniTable_Field* decode_findfield(upb_Decoder* d, - const upb_MiniTable* l, - uint32_t field_number, - int* last_field_index) { - static upb_MiniTable_Field none = {0, 0, 0, 0, 0, 0}; - if (l == NULL) return &none; +static const upb_MiniTable_Sub google_protobuf_ExtensionRangeOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msg_init}, +}; - size_t idx = ((size_t)field_number) - 1; // 0 wraps to SIZE_MAX - if (idx < l->dense_below) { - /* Fastest case: index into dense fields. */ - goto found; - } +static const upb_MiniTable_Field google_protobuf_ExtensionRangeOptions__fields[1] = { + {999, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - if (l->dense_below < l->field_count) { - /* Linear search non-dense fields. Resume scanning from last_field_index - * since fields are usually in order. */ - int last = *last_field_index; - for (idx = last; idx < l->field_count; idx++) { - if (l->fields[idx].number == field_number) { - goto found; - } - } +const upb_MiniTable google_protobuf_ExtensionRangeOptions_msg_init = { + &google_protobuf_ExtensionRangeOptions_submsgs[0], + &google_protobuf_ExtensionRangeOptions__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_Extendable, 0, 255, 0, +}; - for (idx = l->dense_below; idx < last; idx++) { - if (l->fields[idx].number == field_number) { - goto found; - } - } - } +static const upb_MiniTable_Sub google_protobuf_FieldDescriptorProto_submsgs[3] = { + {.subenum = &google_protobuf_FieldDescriptorProto_Label_enum_init}, + {.subenum = &google_protobuf_FieldDescriptorProto_Type_enum_init}, + {.submsg = &google_protobuf_FieldOptions_msg_init}, +}; - if (d->extreg) { - switch (l->ext) { - case kUpb_ExtMode_Extendable: { - const upb_MiniTable_Extension* ext = - _upb_extreg_get(d->extreg, l, field_number); - if (ext) return &ext->field; - break; - } - case kUpb_ExtMode_IsMessageSet: - if (field_number == _UPB_MSGSET_ITEM) { - static upb_MiniTable_Field item = {0, 0, 0, 0, TYPE_MSGSET_ITEM, 0}; - return &item; - } - break; - case kUpb_ExtMode_IsMessageSet_ITEM: - switch (field_number) { - case _UPB_MSGSET_TYPEID: { - static upb_MiniTable_Field type_id = { - 0, 0, 0, 0, TYPE_MSGSET_TYPE_ID, 0}; - return &type_id; - } - case _UPB_MSGSET_MESSAGE: - if (l->fields) { - // We saw type_id previously and succeeded in looking up msg. - return l->fields; - } else { - // TODO: out of order MessageSet. - // This is a very rare case: all serializers will emit in-order - // MessageSets. To hit this case there has to be some kind of - // re-ordering proxy. We should eventually handle this case, but - // not today. - } - break; - } - } - } +static const upb_MiniTable_Field google_protobuf_FieldDescriptorProto__fields[11] = { + {1, UPB_SIZE(24, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(32, 40), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(4, 4), UPB_SIZE(3, 3), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(8, 8), UPB_SIZE(4, 4), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(12, 12), UPB_SIZE(5, 5), 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(40, 56), UPB_SIZE(6, 6), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(48, 72), UPB_SIZE(7, 7), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(56, 88), UPB_SIZE(8, 8), 2, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(16, 16), UPB_SIZE(9, 9), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(60, 96), UPB_SIZE(10, 10), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {17, UPB_SIZE(20, 20), UPB_SIZE(11, 11), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +}; - return &none; /* Unknown field. */ +const upb_MiniTable google_protobuf_FieldDescriptorProto_msg_init = { + &google_protobuf_FieldDescriptorProto_submsgs[0], + &google_protobuf_FieldDescriptorProto__fields[0], + UPB_SIZE(72, 112), 11, kUpb_ExtMode_NonExtendable, 10, 255, 0, +}; -found: - UPB_ASSERT(l->fields[idx].number == field_number); - *last_field_index = idx; - return &l->fields[idx]; -} +static const upb_MiniTable_Sub google_protobuf_OneofDescriptorProto_submsgs[1] = { + {.submsg = &google_protobuf_OneofOptions_msg_init}, +}; -UPB_FORCEINLINE -static const char* decode_wireval(upb_Decoder* d, const char* ptr, - const upb_MiniTable_Field* field, - int wire_type, wireval* val, int* op) { - switch (wire_type) { - case kUpb_WireType_Varint: - ptr = decode_varint64(d, ptr, &val->uint64_val); - *op = varint_ops[field->descriptortype]; - decode_munge(field->descriptortype, val); - return ptr; - case kUpb_WireType_32Bit: - memcpy(&val->uint32_val, ptr, 4); - val->uint32_val = _upb_BigEndian_Swap32(val->uint32_val); - *op = OP_SCALAR_LG2(2); - if (((1 << field->descriptortype) & FIXED32_OK_MASK) == 0) { - *op = OP_UNKNOWN; - } - return ptr + 4; - case kUpb_WireType_64Bit: - memcpy(&val->uint64_val, ptr, 8); - val->uint64_val = _upb_BigEndian_Swap64(val->uint64_val); - *op = OP_SCALAR_LG2(3); - if (((1 << field->descriptortype) & FIXED64_OK_MASK) == 0) { - *op = OP_UNKNOWN; - } - return ptr + 8; - case kUpb_WireType_Delimited: { - int ndx = field->descriptortype; - uint64_t size; - if (upb_FieldMode_Get(field) == kUpb_FieldMode_Array) ndx += TYPE_COUNT; - ptr = decode_varint64(d, ptr, &size); - if (size >= INT32_MAX || ptr - d->end + (int32_t)size > d->limit) { - break; /* Length overflow. */ - } - *op = delim_ops[ndx]; - val->size = size; - return ptr; - } - case kUpb_WireType_StartGroup: - val->uint32_val = field->number; - if (field->descriptortype == kUpb_FieldType_Group) { - *op = OP_SUBMSG; - } else if (field->descriptortype == TYPE_MSGSET_ITEM) { - *op = OP_MSGSET_ITEM; - } else { - *op = OP_UNKNOWN; - } - return ptr; - default: - break; - } - return decode_err(d, kUpb_DecodeStatus_Malformed); -} +static const upb_MiniTable_Field google_protobuf_OneofDescriptorProto__fields[2] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(2, 2), 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -UPB_FORCEINLINE -static const char* decode_known(upb_Decoder* d, const char* ptr, - upb_Message* msg, const upb_MiniTable* layout, - const upb_MiniTable_Field* field, int op, - wireval* val) { - const upb_MiniTable_Sub* subs = layout->subs; - uint8_t mode = field->mode; +const upb_MiniTable google_protobuf_OneofDescriptorProto_msg_init = { + &google_protobuf_OneofDescriptorProto_submsgs[0], + &google_protobuf_OneofDescriptorProto__fields[0], + UPB_SIZE(16, 32), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, +}; - if (UPB_UNLIKELY(mode & kUpb_LabelFlags_IsExtension)) { - const upb_MiniTable_Extension* ext_layout = - (const upb_MiniTable_Extension*)field; - upb_Message_Extension* ext = - _upb_Message_Getorcreateext(msg, ext_layout, &d->arena); - if (UPB_UNLIKELY(!ext)) return decode_err(d, kUpb_DecodeStatus_OutOfMemory); - msg = &ext->data; - subs = &ext->ext->sub; - } +static const upb_MiniTable_Sub google_protobuf_EnumDescriptorProto_submsgs[3] = { + {.submsg = &google_protobuf_EnumValueDescriptorProto_msg_init}, + {.submsg = &google_protobuf_EnumOptions_msg_init}, + {.submsg = &google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init}, +}; - switch (mode & kUpb_FieldMode_Mask) { - case kUpb_FieldMode_Array: - return decode_toarray(d, ptr, msg, subs, field, val, op); - case kUpb_FieldMode_Map: - return decode_tomap(d, ptr, msg, subs, field, val); - case kUpb_FieldMode_Scalar: - return decode_tomsg(d, ptr, msg, subs, field, val, op); - default: - UPB_UNREACHABLE(); - } -} +static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto__fields[5] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 32), UPB_SIZE(2, 2), 1, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 40), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(24, 48), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -static const char* decode_reverse_skip_varint(const char* ptr, uint32_t val) { - uint32_t seen = 0; - do { - ptr--; - seen <<= 7; - seen |= *ptr & 0x7f; - } while (seen != val); - return ptr; -} +const upb_MiniTable google_protobuf_EnumDescriptorProto_msg_init = { + &google_protobuf_EnumDescriptorProto_submsgs[0], + &google_protobuf_EnumDescriptorProto__fields[0], + UPB_SIZE(32, 56), 5, kUpb_ExtMode_NonExtendable, 5, 255, 0, +}; -static const char* decode_unknown(upb_Decoder* d, const char* ptr, - upb_Message* msg, int field_number, - int wire_type, wireval val) { - if (field_number == 0) return decode_err(d, kUpb_DecodeStatus_Malformed); +static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = { + {1, UPB_SIZE(4, 4), UPB_SIZE(1, 1), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 8), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; - // Since unknown fields are the uncommon case, we do a little extra work here - // to walk backwards through the buffer to find the field start. This frees - // up a register in the fast paths (when the field is known), which leads to - // significant speedups in benchmarks. - const char* start = ptr; +const upb_MiniTable google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init = { + NULL, + &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0], + UPB_SIZE(16, 16), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, +}; - if (wire_type == kUpb_WireType_Delimited) ptr += val.size; - if (msg) { - switch (wire_type) { - case kUpb_WireType_Varint: - case kUpb_WireType_Delimited: - start--; - while (start[-1] & 0x80) start--; - break; - case kUpb_WireType_32Bit: - start -= 4; - break; - case kUpb_WireType_64Bit: - start -= 8; - break; - default: - break; - } +static const upb_MiniTable_Sub google_protobuf_EnumValueDescriptorProto_submsgs[1] = { + {.submsg = &google_protobuf_EnumValueOptions_msg_init}, +}; - assert(start == d->debug_valstart); - uint32_t tag = ((uint32_t)field_number << 3) | wire_type; - start = decode_reverse_skip_varint(start, tag); - assert(start == d->debug_tagstart); +static const upb_MiniTable_Field google_protobuf_EnumValueDescriptorProto__fields[3] = { + {1, UPB_SIZE(8, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(4, 4), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 24), UPB_SIZE(3, 3), 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - if (wire_type == kUpb_WireType_StartGroup) { - d->unknown = start; - d->unknown_msg = msg; - ptr = decode_group(d, ptr, NULL, NULL, field_number); - start = d->unknown; - d->unknown_msg = NULL; - d->unknown = NULL; - } - if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { - return decode_err(d, kUpb_DecodeStatus_OutOfMemory); - } - } else if (wire_type == kUpb_WireType_StartGroup) { - ptr = decode_group(d, ptr, NULL, NULL, field_number); - } - return ptr; -} +const upb_MiniTable google_protobuf_EnumValueDescriptorProto_msg_init = { + &google_protobuf_EnumValueDescriptorProto_submsgs[0], + &google_protobuf_EnumValueDescriptorProto__fields[0], + UPB_SIZE(24, 32), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, +}; -UPB_NOINLINE -static const char* decode_msg(upb_Decoder* d, const char* ptr, upb_Message* msg, - const upb_MiniTable* layout) { - int last_field_index = 0; +static const upb_MiniTable_Sub google_protobuf_ServiceDescriptorProto_submsgs[2] = { + {.submsg = &google_protobuf_MethodDescriptorProto_msg_init}, + {.submsg = &google_protobuf_ServiceOptions_msg_init}, +}; -#if UPB_FASTTABLE - // The first time we want to skip fast dispatch, because we may have just been - // invoked by the fast parser to handle a case that it bailed on. - if (!decode_isdone(d, &ptr)) goto nofast; -#endif +static const upb_MiniTable_Field google_protobuf_ServiceDescriptorProto__fields[3] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 32), UPB_SIZE(2, 2), 1, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - while (!decode_isdone(d, &ptr)) { - uint32_t tag; - const upb_MiniTable_Field* field; - int field_number; - int wire_type; - wireval val; - int op; +const upb_MiniTable google_protobuf_ServiceDescriptorProto_msg_init = { + &google_protobuf_ServiceDescriptorProto_submsgs[0], + &google_protobuf_ServiceDescriptorProto__fields[0], + UPB_SIZE(24, 40), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, +}; - if (decode_tryfastdispatch(d, &ptr, msg, layout)) break; +static const upb_MiniTable_Sub google_protobuf_MethodDescriptorProto_submsgs[1] = { + {.submsg = &google_protobuf_MethodOptions_msg_init}, +}; -#if UPB_FASTTABLE - nofast: -#endif +static const upb_MiniTable_Field google_protobuf_MethodDescriptorProto__fields[6] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(20, 40), UPB_SIZE(3, 3), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(28, 56), UPB_SIZE(4, 4), 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(1, 1), UPB_SIZE(5, 5), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(2, 2), UPB_SIZE(6, 6), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +}; -#ifndef NDEBUG - d->debug_tagstart = ptr; -#endif +const upb_MiniTable google_protobuf_MethodDescriptorProto_msg_init = { + &google_protobuf_MethodDescriptorProto_submsgs[0], + &google_protobuf_MethodDescriptorProto__fields[0], + UPB_SIZE(32, 64), 6, kUpb_ExtMode_NonExtendable, 6, 255, 0, +}; - UPB_ASSERT(ptr < d->limit_ptr); - ptr = decode_tag(d, ptr, &tag); - field_number = tag >> 3; - wire_type = tag & 7; +static const upb_MiniTable_Sub google_protobuf_FileOptions_submsgs[2] = { + {.subenum = &google_protobuf_FileOptions_OptimizeMode_enum_init}, + {.submsg = &google_protobuf_UninterpretedOption_msg_init}, +}; -#ifndef NDEBUG - d->debug_valstart = ptr; -#endif +static const upb_MiniTable_Field google_protobuf_FileOptions__fields[21] = { + {1, UPB_SIZE(20, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(28, 40), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(4, 4), UPB_SIZE(3, 3), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(8, 8), UPB_SIZE(4, 4), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {11, UPB_SIZE(36, 56), UPB_SIZE(5, 5), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {16, UPB_SIZE(9, 9), UPB_SIZE(6, 6), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {17, UPB_SIZE(10, 10), UPB_SIZE(7, 7), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {18, UPB_SIZE(11, 11), UPB_SIZE(8, 8), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {20, UPB_SIZE(12, 12), UPB_SIZE(9, 9), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {23, UPB_SIZE(13, 13), UPB_SIZE(10, 10), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {27, UPB_SIZE(14, 14), UPB_SIZE(11, 11), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {31, UPB_SIZE(15, 15), UPB_SIZE(12, 12), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {36, UPB_SIZE(44, 72), UPB_SIZE(13, 13), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {37, UPB_SIZE(52, 88), UPB_SIZE(14, 14), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {39, UPB_SIZE(60, 104), UPB_SIZE(15, 15), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {40, UPB_SIZE(68, 120), UPB_SIZE(16, 16), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {41, UPB_SIZE(76, 136), UPB_SIZE(17, 17), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {42, UPB_SIZE(16, 16), UPB_SIZE(18, 18), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {44, UPB_SIZE(84, 152), UPB_SIZE(19, 19), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {45, UPB_SIZE(92, 168), UPB_SIZE(20, 20), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(100, 184), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - if (wire_type == kUpb_WireType_EndGroup) { - d->end_group = field_number; - return ptr; - } +const upb_MiniTable google_protobuf_FileOptions_msg_init = { + &google_protobuf_FileOptions_submsgs[0], + &google_protobuf_FileOptions__fields[0], + UPB_SIZE(104, 192), 21, kUpb_ExtMode_Extendable, 1, 255, 0, +}; - field = decode_findfield(d, layout, field_number, &last_field_index); - ptr = decode_wireval(d, ptr, field, wire_type, &val, &op); +static const upb_MiniTable_Sub google_protobuf_MessageOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msg_init}, +}; - if (op >= 0) { - ptr = decode_known(d, ptr, msg, layout, field, op, &val); - } else { - switch (op) { - case OP_UNKNOWN: - ptr = decode_unknown(d, ptr, msg, field_number, wire_type, val); - break; - case OP_MSGSET_ITEM: - ptr = decode_msgset(d, ptr, msg, layout); - break; - case OP_MSGSET_TYPEID: { - const upb_MiniTable_Extension* ext = _upb_extreg_get( - d->extreg, layout->subs[0].submsg, val.uint64_val); - if (ext) ((upb_MiniTable*)layout)->fields = &ext->field; - break; - } - } - } - } +static const upb_MiniTable_Field google_protobuf_MessageOptions__fields[5] = { + {1, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(2, 2), UPB_SIZE(2, 2), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(3, 3), UPB_SIZE(3, 3), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(4, 4), UPB_SIZE(4, 4), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(8, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - return UPB_UNLIKELY(layout && layout->required_count) - ? decode_checkrequired(d, ptr, msg, layout) - : ptr; -} +const upb_MiniTable google_protobuf_MessageOptions_msg_init = { + &google_protobuf_MessageOptions_submsgs[0], + &google_protobuf_MessageOptions__fields[0], + UPB_SIZE(16, 16), 5, kUpb_ExtMode_Extendable, 3, 255, 0, +}; -const char* fastdecode_generic(struct upb_Decoder* d, const char* ptr, - upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t data) { - (void)data; - *(uint32_t*)msg |= hasbits; - return decode_msg(d, ptr, msg, decode_totablep(table)); -} +static const upb_MiniTable_Sub google_protobuf_FieldOptions_submsgs[3] = { + {.subenum = &google_protobuf_FieldOptions_CType_enum_init}, + {.subenum = &google_protobuf_FieldOptions_JSType_enum_init}, + {.submsg = &google_protobuf_UninterpretedOption_msg_init}, +}; -static upb_DecodeStatus decode_top(struct upb_Decoder* d, const char* buf, - void* msg, const upb_MiniTable* l) { - if (!decode_tryfastdispatch(d, &buf, msg, l)) { - decode_msg(d, buf, msg, l); - } - if (d->end_group != DECODE_NOGROUP) return kUpb_DecodeStatus_Malformed; - if (d->missing_required) return kUpb_DecodeStatus_MissingRequired; - return kUpb_DecodeStatus_Ok; -} +static const upb_MiniTable_Field google_protobuf_FieldOptions__fields[8] = { + {1, UPB_SIZE(4, 4), UPB_SIZE(1, 1), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 8), UPB_SIZE(2, 2), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(9, 9), UPB_SIZE(3, 3), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(10, 10), UPB_SIZE(4, 4), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(12, 12), UPB_SIZE(5, 5), 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(16, 16), UPB_SIZE(6, 6), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {15, UPB_SIZE(17, 17), UPB_SIZE(7, 7), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(20, 24), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -upb_DecodeStatus upb_Decode(const char* buf, size_t size, void* msg, - const upb_MiniTable* l, - const upb_ExtensionRegistry* extreg, int options, - upb_Arena* arena) { - upb_Decoder state; - unsigned depth = (unsigned)options >> 16; +const upb_MiniTable google_protobuf_FieldOptions_msg_init = { + &google_protobuf_FieldOptions_submsgs[0], + &google_protobuf_FieldOptions__fields[0], + UPB_SIZE(24, 32), 8, kUpb_ExtMode_Extendable, 3, 255, 0, +}; - if (size <= 16) { - memset(&state.patch, 0, 32); - if (size) memcpy(&state.patch, buf, size); - buf = state.patch; - state.end = buf + size; - state.limit = 0; - options &= ~kUpb_DecodeOption_AliasString; // Can't alias patch buf. - } else { - state.end = buf + size - 16; - state.limit = 16; - } +static const upb_MiniTable_Sub google_protobuf_OneofOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msg_init}, +}; - state.extreg = extreg; - state.limit_ptr = state.end; - state.unknown_msg = NULL; - state.depth = depth ? depth : 64; - state.end_group = DECODE_NOGROUP; - state.options = (uint16_t)options; - state.missing_required = false; - state.arena.head = arena->head; - state.arena.last_size = arena->last_size; - state.arena.cleanup_metadata = arena->cleanup_metadata; - state.arena.parent = arena; +static const upb_MiniTable_Field google_protobuf_OneofOptions__fields[1] = { + {999, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - upb_DecodeStatus status = UPB_SETJMP(state.err); - if (UPB_LIKELY(status == kUpb_DecodeStatus_Ok)) { - status = decode_top(&state, buf, msg, l); - } +const upb_MiniTable google_protobuf_OneofOptions_msg_init = { + &google_protobuf_OneofOptions_submsgs[0], + &google_protobuf_OneofOptions__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_Extendable, 0, 255, 0, +}; - arena->head.ptr = state.arena.head.ptr; - arena->head.end = state.arena.head.end; - arena->cleanup_metadata = state.arena.cleanup_metadata; - return status; -} +static const upb_MiniTable_Sub google_protobuf_EnumOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msg_init}, +}; -#undef OP_UNKNOWN -#undef OP_SKIP -#undef OP_SCALAR_LG2 -#undef OP_FIXPCK_LG2 -#undef OP_VARPCK_LG2 -#undef OP_STRING -#undef OP_BYTES -#undef OP_SUBMSG +static const upb_MiniTable_Field google_protobuf_EnumOptions__fields[3] = { + {2, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(2, 2), UPB_SIZE(2, 2), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -/** upb/encode.c ************************************************************/ -/* We encode backwards, to avoid pre-computing lengths (one-pass encode). */ +const upb_MiniTable google_protobuf_EnumOptions_msg_init = { + &google_protobuf_EnumOptions_submsgs[0], + &google_protobuf_EnumOptions__fields[0], + UPB_SIZE(8, 16), 3, kUpb_ExtMode_Extendable, 0, 255, 0, +}; +static const upb_MiniTable_Sub google_protobuf_EnumValueOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msg_init}, +}; -#include -#include +static const upb_MiniTable_Field google_protobuf_EnumValueOptions__fields[2] = { + {1, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; +const upb_MiniTable google_protobuf_EnumValueOptions_msg_init = { + &google_protobuf_EnumValueOptions_submsgs[0], + &google_protobuf_EnumValueOptions__fields[0], + UPB_SIZE(8, 16), 2, kUpb_ExtMode_Extendable, 1, 255, 0, +}; -/* Must be last. */ +static const upb_MiniTable_Sub google_protobuf_ServiceOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msg_init}, +}; -#define UPB_PB_VARINT_MAX_LEN 10 +static const upb_MiniTable_Field google_protobuf_ServiceOptions__fields[2] = { + {33, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -UPB_NOINLINE -static size_t encode_varint64(uint64_t val, char* buf) { - size_t i = 0; - do { - uint8_t byte = val & 0x7fU; - val >>= 7; - if (val) byte |= 0x80U; - buf[i++] = byte; - } while (val); - return i; -} +const upb_MiniTable google_protobuf_ServiceOptions_msg_init = { + &google_protobuf_ServiceOptions_submsgs[0], + &google_protobuf_ServiceOptions__fields[0], + UPB_SIZE(8, 16), 2, kUpb_ExtMode_Extendable, 0, 255, 0, +}; -static uint32_t encode_zz32(int32_t n) { - return ((uint32_t)n << 1) ^ (n >> 31); -} -static uint64_t encode_zz64(int64_t n) { - return ((uint64_t)n << 1) ^ (n >> 63); -} +static const upb_MiniTable_Sub google_protobuf_MethodOptions_submsgs[2] = { + {.subenum = &google_protobuf_MethodOptions_IdempotencyLevel_enum_init}, + {.submsg = &google_protobuf_UninterpretedOption_msg_init}, +}; -typedef struct { - jmp_buf err; - upb_alloc* alloc; - char *buf, *ptr, *limit; - int options; - int depth; - _upb_mapsorter sorter; -} upb_encstate; +static const upb_MiniTable_Field google_protobuf_MethodOptions__fields[3] = { + {33, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {34, UPB_SIZE(4, 4), UPB_SIZE(2, 2), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(8, 8), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -static size_t upb_roundup_pow2(size_t bytes) { - size_t ret = 128; - while (ret < bytes) { - ret *= 2; - } - return ret; -} +const upb_MiniTable google_protobuf_MethodOptions_msg_init = { + &google_protobuf_MethodOptions_submsgs[0], + &google_protobuf_MethodOptions__fields[0], + UPB_SIZE(16, 16), 3, kUpb_ExtMode_Extendable, 0, 255, 0, +}; -UPB_NORETURN static void encode_err(upb_encstate* e) { UPB_LONGJMP(e->err, 1); } +static const upb_MiniTable_Sub google_protobuf_UninterpretedOption_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_NamePart_msg_init}, +}; -UPB_NOINLINE -static void encode_growbuffer(upb_encstate* e, size_t bytes) { - size_t old_size = e->limit - e->buf; - size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr)); - char* new_buf = upb_realloc(e->alloc, e->buf, old_size, new_size); +static const upb_MiniTable_Field google_protobuf_UninterpretedOption__fields[7] = { + {2, UPB_SIZE(4, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(8, 16), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(32, 64), UPB_SIZE(2, 2), kUpb_NoSub, 4, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(40, 72), UPB_SIZE(3, 3), kUpb_NoSub, 3, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(48, 80), UPB_SIZE(4, 4), kUpb_NoSub, 1, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(16, 32), UPB_SIZE(5, 5), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(24, 48), UPB_SIZE(6, 6), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, +}; - if (!new_buf) encode_err(e); +const upb_MiniTable google_protobuf_UninterpretedOption_msg_init = { + &google_protobuf_UninterpretedOption_submsgs[0], + &google_protobuf_UninterpretedOption__fields[0], + UPB_SIZE(56, 88), 7, kUpb_ExtMode_NonExtendable, 0, 255, 0, +}; - /* We want previous data at the end, realloc() put it at the beginning. */ - if (old_size > 0) { - memmove(new_buf + new_size - old_size, e->buf, old_size); - } +static const upb_MiniTable_Field google_protobuf_UninterpretedOption_NamePart__fields[2] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(1, 1), UPB_SIZE(2, 2), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +}; - e->ptr = new_buf + new_size - (e->limit - e->ptr); - e->limit = new_buf + new_size; - e->buf = new_buf; +const upb_MiniTable google_protobuf_UninterpretedOption_NamePart_msg_init = { + NULL, + &google_protobuf_UninterpretedOption_NamePart__fields[0], + UPB_SIZE(16, 24), 2, kUpb_ExtMode_NonExtendable, 2, 255, 2, +}; - e->ptr -= bytes; -} +static const upb_MiniTable_Sub google_protobuf_SourceCodeInfo_submsgs[1] = { + {.submsg = &google_protobuf_SourceCodeInfo_Location_msg_init}, +}; -/* Call to ensure that at least "bytes" bytes are available for writing at - * e->ptr. Returns false if the bytes could not be allocated. */ -UPB_FORCEINLINE -static void encode_reserve(upb_encstate* e, size_t bytes) { - if ((size_t)(e->ptr - e->buf) < bytes) { - encode_growbuffer(e, bytes); - return; - } +static const upb_MiniTable_Field google_protobuf_SourceCodeInfo__fields[1] = { + {1, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - e->ptr -= bytes; -} +const upb_MiniTable google_protobuf_SourceCodeInfo_msg_init = { + &google_protobuf_SourceCodeInfo_submsgs[0], + &google_protobuf_SourceCodeInfo__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, +}; -/* Writes the given bytes to the buffer, handling reserve/advance. */ -static void encode_bytes(upb_encstate* e, const void* data, size_t len) { - if (len == 0) return; /* memcpy() with zero size is UB */ - encode_reserve(e, len); - memcpy(e->ptr, data, len); -} +static const upb_MiniTable_Field google_protobuf_SourceCodeInfo_Location__fields[5] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 16), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(12, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 40), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(28, 56), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -static void encode_fixed64(upb_encstate* e, uint64_t val) { - val = _upb_BigEndian_Swap64(val); - encode_bytes(e, &val, sizeof(uint64_t)); -} +const upb_MiniTable google_protobuf_SourceCodeInfo_Location_msg_init = { + NULL, + &google_protobuf_SourceCodeInfo_Location__fields[0], + UPB_SIZE(32, 64), 5, kUpb_ExtMode_NonExtendable, 4, 255, 0, +}; -static void encode_fixed32(upb_encstate* e, uint32_t val) { - val = _upb_BigEndian_Swap32(val); - encode_bytes(e, &val, sizeof(uint32_t)); -} +static const upb_MiniTable_Sub google_protobuf_GeneratedCodeInfo_submsgs[1] = { + {.submsg = &google_protobuf_GeneratedCodeInfo_Annotation_msg_init}, +}; -UPB_NOINLINE -static void encode_longvarint(upb_encstate* e, uint64_t val) { - size_t len; - char* start; +static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo__fields[1] = { + {1, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - encode_reserve(e, UPB_PB_VARINT_MAX_LEN); - len = encode_varint64(val, e->ptr); - start = e->ptr + UPB_PB_VARINT_MAX_LEN - len; - memmove(start, e->ptr, len); - e->ptr = start; -} +const upb_MiniTable google_protobuf_GeneratedCodeInfo_msg_init = { + &google_protobuf_GeneratedCodeInfo_submsgs[0], + &google_protobuf_GeneratedCodeInfo__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, +}; -UPB_FORCEINLINE -static void encode_varint(upb_encstate* e, uint64_t val) { - if (val < 128 && e->ptr != e->buf) { - --e->ptr; - *e->ptr = val; - } else { - encode_longvarint(e, val); - } -} +static const upb_MiniTable_Sub google_protobuf_GeneratedCodeInfo_Annotation_submsgs[1] = { + {.subenum = &google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init}, +}; -static void encode_double(upb_encstate* e, double d) { - uint64_t u64; - UPB_ASSERT(sizeof(double) == sizeof(uint64_t)); - memcpy(&u64, &d, sizeof(uint64_t)); - encode_fixed64(e, u64); -} +static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo_Annotation__fields[5] = { + {1, UPB_SIZE(16, 16), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(20, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(4, 4), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(8, 8), UPB_SIZE(3, 3), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(12, 12), UPB_SIZE(4, 4), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; -static void encode_float(upb_encstate* e, float d) { - uint32_t u32; - UPB_ASSERT(sizeof(float) == sizeof(uint32_t)); - memcpy(&u32, &d, sizeof(uint32_t)); - encode_fixed32(e, u32); -} +const upb_MiniTable google_protobuf_GeneratedCodeInfo_Annotation_msg_init = { + &google_protobuf_GeneratedCodeInfo_Annotation_submsgs[0], + &google_protobuf_GeneratedCodeInfo_Annotation__fields[0], + UPB_SIZE(32, 40), 5, kUpb_ExtMode_NonExtendable, 5, 255, 0, +}; -static void encode_tag(upb_encstate* e, uint32_t field_number, - uint8_t wire_type) { - encode_varint(e, (field_number << 3) | wire_type); -} +static const upb_MiniTable *messages_layout[27] = { + &google_protobuf_FileDescriptorSet_msg_init, + &google_protobuf_FileDescriptorProto_msg_init, + &google_protobuf_DescriptorProto_msg_init, + &google_protobuf_DescriptorProto_ExtensionRange_msg_init, + &google_protobuf_DescriptorProto_ReservedRange_msg_init, + &google_protobuf_ExtensionRangeOptions_msg_init, + &google_protobuf_FieldDescriptorProto_msg_init, + &google_protobuf_OneofDescriptorProto_msg_init, + &google_protobuf_EnumDescriptorProto_msg_init, + &google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init, + &google_protobuf_EnumValueDescriptorProto_msg_init, + &google_protobuf_ServiceDescriptorProto_msg_init, + &google_protobuf_MethodDescriptorProto_msg_init, + &google_protobuf_FileOptions_msg_init, + &google_protobuf_MessageOptions_msg_init, + &google_protobuf_FieldOptions_msg_init, + &google_protobuf_OneofOptions_msg_init, + &google_protobuf_EnumOptions_msg_init, + &google_protobuf_EnumValueOptions_msg_init, + &google_protobuf_ServiceOptions_msg_init, + &google_protobuf_MethodOptions_msg_init, + &google_protobuf_UninterpretedOption_msg_init, + &google_protobuf_UninterpretedOption_NamePart_msg_init, + &google_protobuf_SourceCodeInfo_msg_init, + &google_protobuf_SourceCodeInfo_Location_msg_init, + &google_protobuf_GeneratedCodeInfo_msg_init, + &google_protobuf_GeneratedCodeInfo_Annotation_msg_init, +}; -static void encode_fixedarray(upb_encstate* e, const upb_Array* arr, - size_t elem_size, uint32_t tag) { - size_t bytes = arr->len * elem_size; - const char* data = _upb_array_constptr(arr); - const char* ptr = data + bytes - elem_size; +const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enum_init = { + 64, + 0, + { + 0x7fffe, + 0x0, + }, +}; - if (tag || !_upb_IsLittleEndian()) { - while (true) { - if (elem_size == 4) { - uint32_t val; - memcpy(&val, ptr, sizeof(val)); - val = _upb_BigEndian_Swap32(val); - encode_bytes(e, &val, elem_size); - } else { - UPB_ASSERT(elem_size == 8); - uint64_t val; - memcpy(&val, ptr, sizeof(val)); - val = _upb_BigEndian_Swap64(val); - encode_bytes(e, &val, elem_size); - } +const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enum_init = { + 64, + 0, + { + 0xe, + 0x0, + }, +}; - if (tag) encode_varint(e, tag); - if (ptr == data) break; - ptr -= elem_size; - } - } else { - encode_bytes(e, data, bytes); - } -} +const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enum_init = { + 64, + 0, + { + 0xe, + 0x0, + }, +}; -static void encode_message(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable* m, size_t* size); +const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; -static void encode_scalar(upb_encstate* e, const void* _field_mem, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { - const char* field_mem = _field_mem; - int wire_type; +const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; -#define CASE(ctype, type, wtype, encodeval) \ - { \ - ctype val = *(ctype*)field_mem; \ - encode_##type(e, encodeval); \ - wire_type = wtype; \ - break; \ - } +const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; - switch (f->descriptortype) { - case kUpb_FieldType_Double: - CASE(double, double, kUpb_WireType_64Bit, val); - case kUpb_FieldType_Float: - CASE(float, float, kUpb_WireType_32Bit, val); - case kUpb_FieldType_Int64: - case kUpb_FieldType_UInt64: - CASE(uint64_t, varint, kUpb_WireType_Varint, val); - case kUpb_FieldType_UInt32: - CASE(uint32_t, varint, kUpb_WireType_Varint, val); - case kUpb_FieldType_Int32: - case kUpb_FieldType_Enum: - CASE(int32_t, varint, kUpb_WireType_Varint, (int64_t)val); - case kUpb_FieldType_SFixed64: - case kUpb_FieldType_Fixed64: - CASE(uint64_t, fixed64, kUpb_WireType_64Bit, val); - case kUpb_FieldType_Fixed32: - case kUpb_FieldType_SFixed32: - CASE(uint32_t, fixed32, kUpb_WireType_32Bit, val); - case kUpb_FieldType_Bool: - CASE(bool, varint, kUpb_WireType_Varint, val); - case kUpb_FieldType_SInt32: - CASE(int32_t, varint, kUpb_WireType_Varint, encode_zz32(val)); - case kUpb_FieldType_SInt64: - CASE(int64_t, varint, kUpb_WireType_Varint, encode_zz64(val)); - case kUpb_FieldType_String: - case kUpb_FieldType_Bytes: { - upb_StringView view = *(upb_StringView*)field_mem; - encode_bytes(e, view.data, view.size); - encode_varint(e, view.size); - wire_type = kUpb_WireType_Delimited; - break; - } - case kUpb_FieldType_Group: { - size_t size; - void* submsg = *(void**)field_mem; - const upb_MiniTable* subm = subs[f->submsg_index].submsg; - if (submsg == NULL) { - return; - } - if (--e->depth == 0) encode_err(e); - encode_tag(e, f->number, kUpb_WireType_EndGroup); - encode_message(e, submsg, subm, &size); - wire_type = kUpb_WireType_StartGroup; - e->depth++; - break; - } - case kUpb_FieldType_Message: { - size_t size; - void* submsg = *(void**)field_mem; - const upb_MiniTable* subm = subs[f->submsg_index].submsg; - if (submsg == NULL) { - return; - } - if (--e->depth == 0) encode_err(e); - encode_message(e, submsg, subm, &size); - encode_varint(e, size); - wire_type = kUpb_WireType_Delimited; - e->depth++; - break; - } - default: - UPB_UNREACHABLE(); - } -#undef CASE +const upb_MiniTable_Enum google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; - encode_tag(e, f->number, wire_type); -} +static const upb_MiniTable_Enum *enums_layout[7] = { + &google_protobuf_FieldDescriptorProto_Type_enum_init, + &google_protobuf_FieldDescriptorProto_Label_enum_init, + &google_protobuf_FileOptions_OptimizeMode_enum_init, + &google_protobuf_FieldOptions_CType_enum_init, + &google_protobuf_FieldOptions_JSType_enum_init, + &google_protobuf_MethodOptions_IdempotencyLevel_enum_init, + &google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init, +}; -static void encode_array(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { - const upb_Array* arr = *UPB_PTR_AT(msg, f->offset, upb_Array*); - bool packed = f->mode & kUpb_LabelFlags_IsPacked; - size_t pre_len = e->limit - e->ptr; +const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout = { + messages_layout, + enums_layout, + NULL, + 27, + 7, + 0, +}; - if (arr == NULL || arr->len == 0) { - return; - } -#define VARINT_CASE(ctype, encode) \ - { \ - const ctype* start = _upb_array_constptr(arr); \ - const ctype* ptr = start + arr->len; \ - uint32_t tag = packed ? 0 : (f->number << 3) | kUpb_WireType_Varint; \ - do { \ - ptr--; \ - encode_varint(e, encode); \ - if (tag) encode_varint(e, tag); \ - } while (ptr != start); \ - } \ - break; -#define TAG(wire_type) (packed ? 0 : (f->number << 3 | wire_type)) - switch (f->descriptortype) { - case kUpb_FieldType_Double: - encode_fixedarray(e, arr, sizeof(double), TAG(kUpb_WireType_64Bit)); - break; - case kUpb_FieldType_Float: - encode_fixedarray(e, arr, sizeof(float), TAG(kUpb_WireType_32Bit)); - break; - case kUpb_FieldType_SFixed64: - case kUpb_FieldType_Fixed64: - encode_fixedarray(e, arr, sizeof(uint64_t), TAG(kUpb_WireType_64Bit)); - break; - case kUpb_FieldType_Fixed32: - case kUpb_FieldType_SFixed32: - encode_fixedarray(e, arr, sizeof(uint32_t), TAG(kUpb_WireType_32Bit)); - break; - case kUpb_FieldType_Int64: - case kUpb_FieldType_UInt64: - VARINT_CASE(uint64_t, *ptr); - case kUpb_FieldType_UInt32: - VARINT_CASE(uint32_t, *ptr); - case kUpb_FieldType_Int32: - case kUpb_FieldType_Enum: - VARINT_CASE(int32_t, (int64_t)*ptr); - case kUpb_FieldType_Bool: - VARINT_CASE(bool, *ptr); - case kUpb_FieldType_SInt32: - VARINT_CASE(int32_t, encode_zz32(*ptr)); - case kUpb_FieldType_SInt64: - VARINT_CASE(int64_t, encode_zz64(*ptr)); - case kUpb_FieldType_String: - case kUpb_FieldType_Bytes: { - const upb_StringView* start = _upb_array_constptr(arr); - const upb_StringView* ptr = start + arr->len; - do { - ptr--; - encode_bytes(e, ptr->data, ptr->size); - encode_varint(e, ptr->size); - encode_tag(e, f->number, kUpb_WireType_Delimited); - } while (ptr != start); - return; - } - case kUpb_FieldType_Group: { - const void* const* start = _upb_array_constptr(arr); - const void* const* ptr = start + arr->len; - const upb_MiniTable* subm = subs[f->submsg_index].submsg; - if (--e->depth == 0) encode_err(e); - do { - size_t size; - ptr--; - encode_tag(e, f->number, kUpb_WireType_EndGroup); - encode_message(e, *ptr, subm, &size); - encode_tag(e, f->number, kUpb_WireType_StartGroup); - } while (ptr != start); - e->depth++; - return; - } - case kUpb_FieldType_Message: { - const void* const* start = _upb_array_constptr(arr); - const void* const* ptr = start + arr->len; - const upb_MiniTable* subm = subs[f->submsg_index].submsg; - if (--e->depth == 0) encode_err(e); - do { - size_t size; - ptr--; - encode_message(e, *ptr, subm, &size); - encode_varint(e, size); - encode_tag(e, f->number, kUpb_WireType_Delimited); - } while (ptr != start); - e->depth++; - return; - } - } -#undef VARINT_CASE - if (packed) { - encode_varint(e, e->limit - e->ptr - pre_len); - encode_tag(e, f->number, kUpb_WireType_Delimited); - } +// Must be last. + +struct upb_ExtensionRegistry { + upb_Arena* arena; + upb_strtable exts; /* Key is upb_MiniTable* concatenated with fieldnum. */ +}; + +#define EXTREG_KEY_SIZE (sizeof(upb_MiniTable*) + sizeof(uint32_t)) + +static void extreg_key(char* buf, const upb_MiniTable* l, uint32_t fieldnum) { + memcpy(buf, &l, sizeof(l)); + memcpy(buf + sizeof(l), &fieldnum, sizeof(fieldnum)); } -static void encode_mapentry(upb_encstate* e, uint32_t number, - const upb_MiniTable* layout, - const upb_MapEntry* ent) { - const upb_MiniTable_Field* key_field = &layout->fields[0]; - const upb_MiniTable_Field* val_field = &layout->fields[1]; - size_t pre_len = e->limit - e->ptr; - size_t size; - encode_scalar(e, &ent->v, layout->subs, val_field); - encode_scalar(e, &ent->k, layout->subs, key_field); - size = (e->limit - e->ptr) - pre_len; - encode_varint(e, size); - encode_tag(e, number, kUpb_WireType_Delimited); +upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena) { + upb_ExtensionRegistry* r = upb_Arena_Malloc(arena, sizeof(*r)); + if (!r) return NULL; + r->arena = arena; + if (!upb_strtable_init(&r->exts, 8, arena)) return NULL; + return r; } -static void encode_map(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { - const upb_Map* map = *UPB_PTR_AT(msg, f->offset, const upb_Map*); - const upb_MiniTable* layout = subs[f->submsg_index].submsg; - UPB_ASSERT(layout->field_count == 2); +bool _upb_extreg_add(upb_ExtensionRegistry* r, + const upb_MiniTable_Extension** e, size_t count) { + char buf[EXTREG_KEY_SIZE]; + const upb_MiniTable_Extension** start = e; + const upb_MiniTable_Extension** end = UPB_PTRADD(e, count); + for (; e < end; e++) { + // TODO: we should gracefully handle the case where this already exists. + // Right now we're only checking for out of memory. + const upb_MiniTable_Extension* ext = *e; + extreg_key(buf, ext->extendee, ext->field.number); + if (!upb_strtable_insert(&r->exts, buf, EXTREG_KEY_SIZE, + upb_value_constptr(ext), r->arena)) { + goto failure; + } + } + return true; - if (map == NULL) return; +failure: + /* Back out the entries previously added. */ + for (end = e, e = start; e < end; e++) { + const upb_MiniTable_Extension* ext = *e; + extreg_key(buf, ext->extendee, ext->field.number); + upb_strtable_remove2(&r->exts, buf, EXTREG_KEY_SIZE, NULL); + } + return false; +} - if (e->options & kUpb_Encode_Deterministic) { - _upb_sortedmap sorted; - _upb_mapsorter_pushmap(&e->sorter, layout->fields[0].descriptortype, map, - &sorted); - upb_MapEntry ent; - while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) { - encode_mapentry(e, f->number, layout, &ent); - } - _upb_mapsorter_popmap(&e->sorter, &sorted); +const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r, + const upb_MiniTable* l, + uint32_t num) { + char buf[EXTREG_KEY_SIZE]; + upb_value v; + extreg_key(buf, l, num); + if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, &v)) { + return upb_value_getconstptr(v); } else { - upb_strtable_iter i; - upb_strtable_begin(&i, &map->table); - for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { - upb_StringView key = upb_strtable_iter_key(&i); - const upb_value val = upb_strtable_iter_value(&i); - upb_MapEntry ent; - _upb_map_fromkey(key, &ent.k, map->key_size); - _upb_map_fromvalue(val, &ent.v, map->val_size); - encode_mapentry(e, f->number, layout, &ent); - } + return NULL; } } -static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { - if (f->presence == 0) { - /* Proto3 presence or map/array. */ - const void* mem = UPB_PTR_AT(msg, f->offset, void); - switch (f->mode >> kUpb_FieldRep_Shift) { - case kUpb_FieldRep_1Byte: { - char ch; - memcpy(&ch, mem, 1); - return ch != 0; - } -#if UINTPTR_MAX == 0xffffffff - case kUpb_FieldRep_Pointer: -#endif - case kUpb_FieldRep_4Byte: { - uint32_t u32; - memcpy(&u32, mem, 4); - return u32 != 0; - } -#if UINTPTR_MAX != 0xffffffff - case kUpb_FieldRep_Pointer: -#endif - case kUpb_FieldRep_8Byte: { - uint64_t u64; - memcpy(&u64, mem, 8); - return u64 != 0; - } - case kUpb_FieldRep_StringView: { - const upb_StringView* str = (const upb_StringView*)mem; - return str->size != 0; - } - default: - UPB_UNREACHABLE(); - } - } else if (f->presence > 0) { - /* Proto2 presence: hasbit. */ - return _upb_hasbit_field(msg, f); - } else { - /* Field is in a oneof. */ - return _upb_getoneofcase_field(msg, f) == f->number; - } -} +// Fast decoder: ~3x the speed of decode.c, but requires x86-64/ARM64. +// Also the table size grows by 2x. +// +// Could potentially be ported to other 64-bit archs that pass at least six +// arguments in registers and have 8 unused high bits in pointers. +// +// The overall design is to create specialized functions for every possible +// field type (eg. oneof boolean field with a 1 byte tag) and then dispatch +// to the specialized function as quickly as possible. -static void encode_field(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field) { - switch (upb_FieldMode_Get(field)) { - case kUpb_FieldMode_Array: - encode_array(e, msg, subs, field); - break; - case kUpb_FieldMode_Map: - encode_map(e, msg, subs, field); - break; - case kUpb_FieldMode_Scalar: - encode_scalar(e, UPB_PTR_AT(msg, field->offset, void), subs, field); - break; - default: - UPB_UNREACHABLE(); - } -} -/* message MessageSet { - * repeated group Item = 1 { - * required int32 type_id = 2; - * required string message = 3; - * } - * } */ -static void encode_msgset_item(upb_encstate* e, - const upb_Message_Extension* ext) { - size_t size; - encode_tag(e, 1, kUpb_WireType_EndGroup); - encode_message(e, ext->data.ptr, ext->ext->sub.submsg, &size); - encode_varint(e, size); - encode_tag(e, 3, kUpb_WireType_Delimited); - encode_varint(e, ext->ext->field.number); - encode_tag(e, 2, kUpb_WireType_Varint); - encode_tag(e, 1, kUpb_WireType_StartGroup); -} -static void encode_message(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable* m, size_t* size) { - size_t pre_len = e->limit - e->ptr; +// Must be last. - if ((e->options & kUpb_Encode_CheckRequired) && m->required_count) { - uint64_t msg_head; - memcpy(&msg_head, msg, 8); - msg_head = _upb_BigEndian_Swap64(msg_head); - if (upb_MiniTable_requiredmask(m) & ~msg_head) { - encode_err(e); - } - } +#if UPB_FASTTABLE - if ((e->options & kUpb_Encode_SkipUnknown) == 0) { - size_t unknown_size; - const char* unknown = upb_Message_GetUnknown(msg, &unknown_size); +// The standard set of arguments passed to each parsing function. +// Thanks to x86-64 calling conventions, these will stay in registers. +#define UPB_PARSE_PARAMS \ + upb_Decoder *d, const char *ptr, upb_Message *msg, intptr_t table, \ + uint64_t hasbits, uint64_t data - if (unknown) { - encode_bytes(e, unknown, unknown_size); - } - } +#define UPB_PARSE_ARGS d, ptr, msg, table, hasbits, data - if (m->ext != kUpb_ExtMode_NonExtendable) { - /* Encode all extensions together. Unlike C++, we do not attempt to keep - * these in field number order relative to normal fields or even to each - * other. */ - size_t ext_count; - const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &ext_count); - if (ext_count) { - const upb_Message_Extension* end = ext + ext_count; - for (; ext != end; ext++) { - if (UPB_UNLIKELY(m->ext == kUpb_ExtMode_IsMessageSet)) { - encode_msgset_item(e, ext); - } else { - encode_field(e, &ext->data, &ext->ext->sub, &ext->ext->field); - } - } - } - } +#define RETURN_GENERIC(m) \ + /* Uncomment either of these for debugging purposes. */ \ + /* fprintf(stderr, m); */ \ + /*__builtin_trap(); */ \ + return _upb_FastDecoder_DecodeGeneric(d, ptr, msg, table, hasbits, 0); - if (m->field_count) { - const upb_MiniTable_Field* f = &m->fields[m->field_count]; - const upb_MiniTable_Field* first = &m->fields[0]; - while (f != first) { - f--; - if (encode_shouldencode(e, msg, m->subs, f)) { - encode_field(e, msg, m->subs, f); - } - } - } +typedef enum { + CARD_s = 0, /* Singular (optional, non-repeated) */ + CARD_o = 1, /* Oneof */ + CARD_r = 2, /* Repeated */ + CARD_p = 3 /* Packed Repeated */ +} upb_card; - *size = (e->limit - e->ptr) - pre_len; +UPB_NOINLINE +static const char* fastdecode_isdonefallback(UPB_PARSE_PARAMS) { + int overrun = data; + int status; + ptr = _upb_Decoder_IsDoneFallbackInline(d, ptr, overrun, &status); + if (ptr == NULL) _upb_FastDecoder_ErrorJmp(d, status); + data = _upb_FastDecoder_LoadTag(ptr); + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); } -char* upb_Encode(const void* msg, const upb_MiniTable* l, int options, - upb_Arena* arena, size_t* size) { - upb_encstate e; - unsigned depth = (unsigned)options >> 16; - - e.alloc = upb_Arena_Alloc(arena); - e.buf = NULL; - e.limit = NULL; - e.ptr = NULL; - e.depth = depth ? depth : 64; - e.options = options; - _upb_mapsorter_init(&e.sorter); - char* ret = NULL; - - if (UPB_SETJMP(e.err)) { - *size = 0; - ret = NULL; - } else { - encode_message(&e, msg, l, size); - *size = e.limit - e.ptr; - if (*size == 0) { - static char ch; - ret = &ch; +UPB_FORCEINLINE +static const char* fastdecode_dispatch(UPB_PARSE_PARAMS) { + if (UPB_UNLIKELY(ptr >= d->limit_ptr)) { + int overrun = ptr - d->end; + if (UPB_LIKELY(overrun == d->limit)) { + // Parse is finished. + *(uint32_t*)msg |= hasbits; // Sync hasbits. + const upb_MiniTable* l = decode_totablep(table); + return UPB_UNLIKELY(l->required_count) + ? _upb_Decoder_CheckRequired(d, ptr, msg, l) + : ptr; } else { - UPB_ASSERT(e.ptr); - ret = e.ptr; + data = overrun; + UPB_MUSTTAIL return fastdecode_isdonefallback(UPB_PARSE_ARGS); } } - _upb_mapsorter_destroy(&e.sorter); - return ret; + // Read two bytes of tag data (for a one-byte tag, the high byte is junk). + data = _upb_FastDecoder_LoadTag(ptr); + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); } -/** upb/msg.c ************************************************************/ - - -/** upb_Message - * *******************************************************************/ - -static const size_t overhead = sizeof(upb_Message_InternalData); +UPB_FORCEINLINE +static bool fastdecode_checktag(uint16_t data, int tagbytes) { + if (tagbytes == 1) { + return (data & 0xff) == 0; + } else { + return data == 0; + } +} -static const upb_Message_Internal* upb_Message_Getinternal_const( - const upb_Message* msg) { - ptrdiff_t size = sizeof(upb_Message_Internal); - return (upb_Message_Internal*)((char*)msg - size); +UPB_FORCEINLINE +static const char* fastdecode_longsize(const char* ptr, int* size) { + int i; + UPB_ASSERT(*size & 0x80); + *size &= 0xff; + for (i = 0; i < 3; i++) { + ptr++; + size_t byte = (uint8_t)ptr[-1]; + *size += (byte - 1) << (7 + 7 * i); + if (UPB_LIKELY((byte & 0x80) == 0)) return ptr; + } + ptr++; + size_t byte = (uint8_t)ptr[-1]; + // len is limited by 2gb not 4gb, hence 8 and not 16 as normally expected + // for a 32 bit varint. + if (UPB_UNLIKELY(byte >= 8)) return NULL; + *size += (byte - 1) << 28; + return ptr; } -upb_Message* _upb_Message_New(const upb_MiniTable* l, upb_Arena* a) { - return _upb_Message_New_inl(l, a); +UPB_FORCEINLINE +static bool fastdecode_boundscheck(const char* ptr, size_t len, + const char* end) { + uintptr_t uptr = (uintptr_t)ptr; + uintptr_t uend = (uintptr_t)end + 16; + uintptr_t res = uptr + len; + return res < uptr || res > uend; } -void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l) { - void* mem = UPB_PTR_AT(msg, -sizeof(upb_Message_Internal), char); - memset(mem, 0, upb_msg_sizeof(l)); +UPB_FORCEINLINE +static bool fastdecode_boundscheck2(const char* ptr, size_t len, + const char* end) { + // This is one extra branch compared to the more normal: + // return (size_t)(end - ptr) < size; + // However it is one less computation if we are just about to use "ptr + len": + // https://godbolt.org/z/35YGPz + // In microbenchmarks this shows an overall 4% improvement. + uintptr_t uptr = (uintptr_t)ptr; + uintptr_t uend = (uintptr_t)end; + uintptr_t res = uptr + len; + return res < uptr || res > uend; } -static bool realloc_internal(upb_Message* msg, size_t need, upb_Arena* arena) { - upb_Message_Internal* in = upb_Message_Getinternal(msg); - if (!in->internal) { - /* No internal data, allocate from scratch. */ - size_t size = UPB_MAX(128, _upb_Log2CeilingSize(need + overhead)); - upb_Message_InternalData* internal = upb_Arena_Malloc(arena, size); - if (!internal) return false; - internal->size = size; - internal->unknown_end = overhead; - internal->ext_begin = size; - in->internal = internal; - } else if (in->internal->ext_begin - in->internal->unknown_end < need) { - /* Internal data is too small, reallocate. */ - size_t new_size = _upb_Log2CeilingSize(in->internal->size + need); - size_t ext_bytes = in->internal->size - in->internal->ext_begin; - size_t new_ext_begin = new_size - ext_bytes; - upb_Message_InternalData* internal = - upb_Arena_Realloc(arena, in->internal, in->internal->size, new_size); - if (!internal) return false; - if (ext_bytes) { - /* Need to move extension data to the end. */ - char* ptr = (char*)internal; - memmove(ptr + new_ext_begin, ptr + internal->ext_begin, ext_bytes); - } - internal->ext_begin = new_ext_begin; - internal->size = new_size; - in->internal = internal; +typedef const char* fastdecode_delimfunc(upb_Decoder* d, const char* ptr, + void* ctx); + +UPB_FORCEINLINE +static const char* fastdecode_delimited(upb_Decoder* d, const char* ptr, + fastdecode_delimfunc* func, void* ctx) { + ptr++; + int len = (int8_t)ptr[-1]; + if (fastdecode_boundscheck2(ptr, len, d->limit_ptr)) { + // Slow case: Sub-message is >=128 bytes and/or exceeds the current buffer. + // If it exceeds the buffer limit, limit/limit_ptr will change during + // sub-message parsing, so we need to preserve delta, not limit. + if (UPB_UNLIKELY(len & 0x80)) { + // Size varint >1 byte (length >= 128). + ptr = fastdecode_longsize(ptr, &len); + if (!ptr) { + // Corrupt wire format: size exceeded INT_MAX. + return NULL; + } + } + if (ptr - d->end + (int)len > d->limit) { + // Corrupt wire format: invalid limit. + return NULL; + } + int delta = _upb_Decoder_PushLimit(d, ptr, len); + ptr = func(d, ptr, ctx); + _upb_Decoder_PopLimit(d, ptr, delta); + } else { + // Fast case: Sub-message is <128 bytes and fits in the current buffer. + // This means we can preserve limit/limit_ptr verbatim. + const char* saved_limit_ptr = d->limit_ptr; + int saved_limit = d->limit; + d->limit_ptr = ptr + len; + d->limit = d->limit_ptr - d->end; + UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); + ptr = func(d, ptr, ctx); + d->limit_ptr = saved_limit_ptr; + d->limit = saved_limit; + UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); } - UPB_ASSERT(in->internal->ext_begin - in->internal->unknown_end >= need); - return true; + return ptr; } -bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, - upb_Arena* arena) { - if (!realloc_internal(msg, len, arena)) return false; - upb_Message_Internal* in = upb_Message_Getinternal(msg); - memcpy(UPB_PTR_AT(in->internal, in->internal->unknown_end, char), data, len); - in->internal->unknown_end += len; - return true; -} +/* singular, oneof, repeated field handling ***********************************/ -void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) { - upb_Message_Internal* in = upb_Message_Getinternal(msg); - if (in->internal) { - in->internal->unknown_end = overhead; +typedef struct { + upb_Array* arr; + void* end; +} fastdecode_arr; + +typedef enum { + FD_NEXT_ATLIMIT, + FD_NEXT_SAMEFIELD, + FD_NEXT_OTHERFIELD +} fastdecode_next; + +typedef struct { + void* dst; + fastdecode_next next; + uint32_t tag; +} fastdecode_nextret; + +UPB_FORCEINLINE +static void* fastdecode_resizearr(upb_Decoder* d, void* dst, + fastdecode_arr* farr, int valbytes) { + if (UPB_UNLIKELY(dst == farr->end)) { + size_t old_size = farr->arr->capacity; + size_t old_bytes = old_size * valbytes; + size_t new_size = old_size * 2; + size_t new_bytes = new_size * valbytes; + char* old_ptr = _upb_array_ptr(farr->arr); + char* new_ptr = upb_Arena_Realloc(&d->arena, old_ptr, old_bytes, new_bytes); + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); + farr->arr->capacity = new_size; + farr->arr->data = _upb_array_tagptr(new_ptr, elem_size_lg2); + dst = (void*)(new_ptr + (old_size * valbytes)); + farr->end = (void*)(new_ptr + (new_size * valbytes)); } + return dst; } -const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len) { - const upb_Message_Internal* in = upb_Message_Getinternal_const(msg); - if (in->internal) { - *len = in->internal->unknown_end - overhead; - return (char*)(in->internal + 1); +UPB_FORCEINLINE +static bool fastdecode_tagmatch(uint32_t tag, uint64_t data, int tagbytes) { + if (tagbytes == 1) { + return (uint8_t)tag == (uint8_t)data; } else { - *len = 0; - return NULL; + return (uint16_t)tag == (uint16_t)data; } } -const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg, - size_t* count) { - const upb_Message_Internal* in = upb_Message_Getinternal_const(msg); - if (in->internal) { - *count = (in->internal->size - in->internal->ext_begin) / - sizeof(upb_Message_Extension); - return UPB_PTR_AT(in->internal, in->internal->ext_begin, void); - } else { - *count = 0; - return NULL; - } +UPB_FORCEINLINE +static void fastdecode_commitarr(void* dst, fastdecode_arr* farr, + int valbytes) { + farr->arr->size = + (size_t)((char*)dst - (char*)_upb_array_ptr(farr->arr)) / valbytes; } -const upb_Message_Extension* _upb_Message_Getext( - const upb_Message* msg, const upb_MiniTable_Extension* e) { - size_t n; - const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &n); +UPB_FORCEINLINE +static fastdecode_nextret fastdecode_nextrepeated(upb_Decoder* d, void* dst, + const char** ptr, + fastdecode_arr* farr, + uint64_t data, int tagbytes, + int valbytes) { + fastdecode_nextret ret; + dst = (char*)dst + valbytes; - /* For now we use linear search exclusively to find extensions. If this - * becomes an issue due to messages with lots of extensions, we can introduce - * a table of some sort. */ - for (size_t i = 0; i < n; i++) { - if (ext[i].ext == e) { - return &ext[i]; + if (UPB_LIKELY(!_upb_Decoder_IsDone(d, ptr))) { + ret.tag = _upb_FastDecoder_LoadTag(*ptr); + if (fastdecode_tagmatch(ret.tag, data, tagbytes)) { + ret.next = FD_NEXT_SAMEFIELD; + } else { + fastdecode_commitarr(dst, farr, valbytes); + ret.next = FD_NEXT_OTHERFIELD; } + } else { + fastdecode_commitarr(dst, farr, valbytes); + ret.next = FD_NEXT_ATLIMIT; } - return NULL; + ret.dst = dst; + return ret; } -void _upb_Message_Clearext(upb_Message* msg, - const upb_MiniTable_Extension* ext_l) { - upb_Message_Internal* in = upb_Message_Getinternal(msg); - if (!in->internal) return; - const upb_Message_Extension* base = - UPB_PTR_AT(in->internal, in->internal->ext_begin, void); - upb_Message_Extension* ext = - (upb_Message_Extension*)_upb_Message_Getext(msg, ext_l); - if (ext) { - *ext = *base; - in->internal->ext_begin += sizeof(upb_Message_Extension); - } +UPB_FORCEINLINE +static void* fastdecode_fieldmem(upb_Message* msg, uint64_t data) { + size_t ofs = data >> 48; + return (char*)msg + ofs; } -upb_Message_Extension* _upb_Message_Getorcreateext( - upb_Message* msg, const upb_MiniTable_Extension* e, upb_Arena* arena) { - upb_Message_Extension* ext = - (upb_Message_Extension*)_upb_Message_Getext(msg, e); - if (ext) return ext; - if (!realloc_internal(msg, sizeof(upb_Message_Extension), arena)) return NULL; - upb_Message_Internal* in = upb_Message_Getinternal(msg); - in->internal->ext_begin -= sizeof(upb_Message_Extension); - ext = UPB_PTR_AT(in->internal, in->internal->ext_begin, void); - memset(ext, 0, sizeof(upb_Message_Extension)); - ext->ext = e; - return ext; +UPB_FORCEINLINE +static void* fastdecode_getfield(upb_Decoder* d, const char* ptr, + upb_Message* msg, uint64_t* data, + uint64_t* hasbits, fastdecode_arr* farr, + int valbytes, upb_card card) { + switch (card) { + case CARD_s: { + uint8_t hasbit_index = *data >> 24; + // Set hasbit and return pointer to scalar field. + *hasbits |= 1ull << hasbit_index; + return fastdecode_fieldmem(msg, *data); + } + case CARD_o: { + uint16_t case_ofs = *data >> 32; + uint32_t* oneof_case = UPB_PTR_AT(msg, case_ofs, uint32_t); + uint8_t field_number = *data >> 24; + *oneof_case = field_number; + return fastdecode_fieldmem(msg, *data); + } + case CARD_r: { + // Get pointer to upb_Array and allocate/expand if necessary. + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); + upb_Array** arr_p = fastdecode_fieldmem(msg, *data); + char* begin; + *(uint32_t*)msg |= *hasbits; + *hasbits = 0; + if (UPB_LIKELY(!*arr_p)) { + farr->arr = _upb_Array_New(&d->arena, 8, elem_size_lg2); + *arr_p = farr->arr; + } else { + farr->arr = *arr_p; + } + begin = _upb_array_ptr(farr->arr); + farr->end = begin + (farr->arr->capacity * valbytes); + *data = _upb_FastDecoder_LoadTag(ptr); + return begin + (farr->arr->size * valbytes); + } + default: + UPB_UNREACHABLE(); + } } -size_t upb_Message_ExtensionCount(const upb_Message* msg) { - size_t count; - _upb_Message_Getexts(msg, &count); - return count; +UPB_FORCEINLINE +static bool fastdecode_flippacked(uint64_t* data, int tagbytes) { + *data ^= (0x2 ^ 0x0); // Patch data to match packed wiretype. + return fastdecode_checktag(*data, tagbytes); } -/** upb_Array *****************************************************************/ - -bool _upb_array_realloc(upb_Array* arr, size_t min_size, upb_Arena* arena) { - size_t new_size = UPB_MAX(arr->size, 4); - int elem_size_lg2 = arr->data & 7; - size_t old_bytes = arr->size << elem_size_lg2; - size_t new_bytes; - void* ptr = _upb_array_ptr(arr); - - /* Log2 ceiling of size. */ - while (new_size < min_size) new_size *= 2; +#define FASTDECODE_CHECKPACKED(tagbytes, card, func) \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) { \ + UPB_MUSTTAIL return func(UPB_PARSE_ARGS); \ + } \ + RETURN_GENERIC("packed check tag mismatch\n"); \ + } - new_bytes = new_size << elem_size_lg2; - ptr = upb_Arena_Realloc(arena, ptr, old_bytes, new_bytes); +/* varint fields **************************************************************/ - if (!ptr) { - return false; +UPB_FORCEINLINE +static uint64_t fastdecode_munge(uint64_t val, int valbytes, bool zigzag) { + if (valbytes == 1) { + return val != 0; + } else if (zigzag) { + if (valbytes == 4) { + uint32_t n = val; + return (n >> 1) ^ -(int32_t)(n & 1); + } else if (valbytes == 8) { + return (val >> 1) ^ -(int64_t)(val & 1); + } + UPB_UNREACHABLE(); } - - arr->data = _upb_tag_arrptr(ptr, elem_size_lg2); - arr->size = new_size; - return true; + return val; } -static upb_Array* getorcreate_array(upb_Array** arr_ptr, int elem_size_lg2, - upb_Arena* arena) { - upb_Array* arr = *arr_ptr; - if (!arr) { - arr = _upb_Array_New(arena, 4, elem_size_lg2); - if (!arr) return NULL; - *arr_ptr = arr; - } - return arr; +UPB_FORCEINLINE +static const char* fastdecode_varint64(const char* ptr, uint64_t* val) { + ptr++; + *val = (uint8_t)ptr[-1]; + if (UPB_UNLIKELY(*val & 0x80)) { + int i; + for (i = 0; i < 8; i++) { + ptr++; + uint64_t byte = (uint8_t)ptr[-1]; + *val += (byte - 1) << (7 + 7 * i); + if (UPB_LIKELY((byte & 0x80) == 0)) goto done; + } + ptr++; + uint64_t byte = (uint8_t)ptr[-1]; + if (byte > 1) { + return NULL; + } + *val += (byte - 1) << 63; + } +done: + UPB_ASSUME(ptr != NULL); + return ptr; } -void* _upb_Array_Resize_fallback(upb_Array** arr_ptr, size_t size, - int elem_size_lg2, upb_Arena* arena) { - upb_Array* arr = getorcreate_array(arr_ptr, elem_size_lg2, arena); - return arr && _upb_Array_Resize(arr, size, arena) ? _upb_array_ptr(arr) - : NULL; -} +#define FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, packed) \ + uint64_t val; \ + void* dst; \ + fastdecode_arr farr; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, card, packed); \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ + card); \ + if (card == CARD_r) { \ + if (UPB_UNLIKELY(!dst)) { \ + RETURN_GENERIC("need array resize\n"); \ + } \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_varint64(ptr, &val); \ + if (ptr == NULL) _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + val = fastdecode_munge(val, valbytes, zigzag); \ + memcpy(dst, &val, valbytes); \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, valbytes); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); -bool _upb_Array_Append_fallback(upb_Array** arr_ptr, const void* value, - int elem_size_lg2, upb_Arena* arena) { - upb_Array* arr = getorcreate_array(arr_ptr, elem_size_lg2, arena); - if (!arr) return false; +typedef struct { + uint8_t valbytes; + bool zigzag; + void* dst; + fastdecode_arr farr; +} fastdecode_varintdata; - size_t elems = arr->len; +UPB_FORCEINLINE +static const char* fastdecode_topackedvarint(upb_Decoder* d, const char* ptr, + void* ctx) { + fastdecode_varintdata* data = ctx; + void* dst = data->dst; + uint64_t val; - if (!_upb_Array_Resize(arr, elems + 1, arena)) { - return false; + while (!_upb_Decoder_IsDone(d, &ptr)) { + dst = fastdecode_resizearr(d, dst, &data->farr, data->valbytes); + ptr = fastdecode_varint64(ptr, &val); + if (ptr == NULL) return NULL; + val = fastdecode_munge(val, data->valbytes, data->zigzag); + memcpy(dst, &val, data->valbytes); + dst = (char*)dst + data->valbytes; } - char* data = _upb_array_ptr(arr); - memcpy(data + (elems << elem_size_lg2), value, 1 << elem_size_lg2); - return true; + fastdecode_commitarr(dst, &data->farr, data->valbytes); + return ptr; } -/** upb_Map *******************************************************************/ - -upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size) { - upb_Map* map = upb_Arena_Malloc(a, sizeof(upb_Map)); +#define FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, zigzag, unpacked) \ + fastdecode_varintdata ctx = {valbytes, zigzag}; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked); \ + \ + ctx.dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &ctx.farr, \ + valbytes, CARD_r); \ + if (UPB_UNLIKELY(!ctx.dst)) { \ + RETURN_GENERIC("need array resize\n"); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_delimited(d, ptr, &fastdecode_topackedvarint, &ctx); \ + \ + if (UPB_UNLIKELY(ptr == NULL)) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(d, ptr, msg, table, hasbits, 0); - if (!map) { - return NULL; +#define FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, unpacked, packed) \ + if (card == CARD_p) { \ + FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, zigzag, unpacked); \ + } else { \ + FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, packed); \ } - upb_strtable_init(&map->table, 4, a); - map->key_size = key_size; - map->val_size = value_size; - - return map; -} - -static void _upb_mapsorter_getkeys(const void* _a, const void* _b, void* a_key, - void* b_key, size_t size) { - const upb_tabent* const* a = _a; - const upb_tabent* const* b = _b; - upb_StringView a_tabkey = upb_tabstrview((*a)->key); - upb_StringView b_tabkey = upb_tabstrview((*b)->key); - _upb_map_fromkey(a_tabkey, a_key, size); - _upb_map_fromkey(b_tabkey, b_key, size); -} +#define z_ZZ true +#define b_ZZ false +#define v_ZZ false -#define UPB_COMPARE_INTEGERS(a, b) ((a) < (b) ? -1 : ((a) == (b) ? 0 : 1)) +/* Generate all combinations: + * {s,o,r,p} x {b1,v4,z4,v8,z8} x {1bt,2bt} */ -static int _upb_mapsorter_cmpi64(const void* _a, const void* _b) { - int64_t a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); - return UPB_COMPARE_INTEGERS(a, b); -} +#define F(card, type, valbytes, tagbytes) \ + UPB_NOINLINE \ + const char* upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ + CARD_##card, type##_ZZ, \ + upb_pr##type##valbytes##_##tagbytes##bt, \ + upb_pp##type##valbytes##_##tagbytes##bt); \ + } -static int _upb_mapsorter_cmpu64(const void* _a, const void* _b) { - uint64_t a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); - return UPB_COMPARE_INTEGERS(a, b); -} +#define TYPES(card, tagbytes) \ + F(card, b, 1, tagbytes) \ + F(card, v, 4, tagbytes) \ + F(card, v, 8, tagbytes) \ + F(card, z, 4, tagbytes) \ + F(card, z, 8, tagbytes) -static int _upb_mapsorter_cmpi32(const void* _a, const void* _b) { - int32_t a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); - return UPB_COMPARE_INTEGERS(a, b); -} +#define TAGBYTES(card) \ + TYPES(card, 1) \ + TYPES(card, 2) -static int _upb_mapsorter_cmpu32(const void* _a, const void* _b) { - uint32_t a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); - return UPB_COMPARE_INTEGERS(a, b); -} +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) +TAGBYTES(p) -static int _upb_mapsorter_cmpbool(const void* _a, const void* _b) { - bool a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 1); - return UPB_COMPARE_INTEGERS(a, b); -} +#undef z_ZZ +#undef b_ZZ +#undef v_ZZ +#undef o_ONEOF +#undef s_ONEOF +#undef r_ONEOF +#undef F +#undef TYPES +#undef TAGBYTES +#undef FASTDECODE_UNPACKEDVARINT +#undef FASTDECODE_PACKEDVARINT +#undef FASTDECODE_VARINT -static int _upb_mapsorter_cmpstr(const void* _a, const void* _b) { - upb_StringView a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, UPB_MAPTYPE_STRING); - size_t common_size = UPB_MIN(a.size, b.size); - int cmp = memcmp(a.data, b.data, common_size); - if (cmp) return -cmp; - return UPB_COMPARE_INTEGERS(a.size, b.size); -} +/* fixed fields ***************************************************************/ -#undef UPB_COMPARE_INTEGERS +#define FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, packed) \ + void* dst; \ + fastdecode_arr farr; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, card, packed) \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ + card); \ + if (card == CARD_r) { \ + if (UPB_UNLIKELY(!dst)) { \ + RETURN_GENERIC("couldn't allocate array in arena\n"); \ + } \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ + } \ + \ + ptr += tagbytes; \ + memcpy(dst, ptr, valbytes); \ + ptr += valbytes; \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, valbytes); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); -bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, - const upb_Map* map, _upb_sortedmap* sorted) { - int map_size = _upb_Map_Size(map); - sorted->start = s->size; - sorted->pos = sorted->start; - sorted->end = sorted->start + map_size; - - /* Grow s->entries if necessary. */ - if (sorted->end > s->cap) { - s->cap = _upb_Log2CeilingSize(sorted->end); - s->entries = realloc(s->entries, s->cap * sizeof(*s->entries)); - if (!s->entries) return false; - } - - s->size = sorted->end; +#define FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, unpacked) \ + FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked) \ + \ + ptr += tagbytes; \ + int size = (uint8_t)ptr[0]; \ + ptr++; \ + if (size & 0x80) { \ + ptr = fastdecode_longsize(ptr, &size); \ + } \ + \ + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr) || \ + (size % valbytes) != 0)) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + upb_Array** arr_p = fastdecode_fieldmem(msg, data); \ + upb_Array* arr = *arr_p; \ + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); \ + int elems = size / valbytes; \ + \ + if (UPB_LIKELY(!arr)) { \ + *arr_p = arr = _upb_Array_New(&d->arena, elems, elem_size_lg2); \ + if (!arr) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + } \ + } else { \ + _upb_Array_Resize(arr, elems, &d->arena); \ + } \ + \ + char* dst = _upb_array_ptr(arr); \ + memcpy(dst, ptr, size); \ + arr->size = elems; \ + \ + ptr += size; \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); - /* Copy non-empty entries from the table to s->entries. */ - upb_tabent const** dst = &s->entries[sorted->start]; - const upb_tabent* src = map->table.t.entries; - const upb_tabent* end = src + upb_table_size(&map->table.t); - for (; src < end; src++) { - if (!upb_tabent_isempty(src)) { - *dst = src; - dst++; - } +#define FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, unpacked, packed) \ + if (card == CARD_p) { \ + FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, unpacked); \ + } else { \ + FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, packed); \ } - UPB_ASSERT(dst == &s->entries[sorted->end]); - - /* Sort entries according to the key type. */ - int (*compar)(const void*, const void*); +/* Generate all combinations: + * {s,o,r,p} x {f4,f8} x {1bt,2bt} */ - switch (key_type) { - case kUpb_FieldType_Int64: - case kUpb_FieldType_SFixed64: - case kUpb_FieldType_SInt64: - compar = _upb_mapsorter_cmpi64; - break; - case kUpb_FieldType_UInt64: - case kUpb_FieldType_Fixed64: - compar = _upb_mapsorter_cmpu64; - break; - case kUpb_FieldType_Int32: - case kUpb_FieldType_SInt32: - case kUpb_FieldType_SFixed32: - case kUpb_FieldType_Enum: - compar = _upb_mapsorter_cmpi32; - break; - case kUpb_FieldType_UInt32: - case kUpb_FieldType_Fixed32: - compar = _upb_mapsorter_cmpu32; - break; - case kUpb_FieldType_Bool: - compar = _upb_mapsorter_cmpbool; - break; - case kUpb_FieldType_String: - case kUpb_FieldType_Bytes: - compar = _upb_mapsorter_cmpstr; - break; - default: - UPB_UNREACHABLE(); +#define F(card, valbytes, tagbytes) \ + UPB_NOINLINE \ + const char* upb_p##card##f##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ + CARD_##card, upb_ppf##valbytes##_##tagbytes##bt, \ + upb_prf##valbytes##_##tagbytes##bt); \ } - qsort(&s->entries[sorted->start], map_size, sizeof(*s->entries), compar); - return true; -} - -/** upb_ExtensionRegistry - * ****************************************************************/ +#define TYPES(card, tagbytes) \ + F(card, 4, tagbytes) \ + F(card, 8, tagbytes) -struct upb_ExtensionRegistry { - upb_Arena* arena; - upb_strtable exts; /* Key is upb_MiniTable* concatenated with fieldnum. */ -}; +#define TAGBYTES(card) \ + TYPES(card, 1) \ + TYPES(card, 2) -#define EXTREG_KEY_SIZE (sizeof(upb_MiniTable*) + sizeof(uint32_t)) +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) +TAGBYTES(p) -static void extreg_key(char* buf, const upb_MiniTable* l, uint32_t fieldnum) { - memcpy(buf, &l, sizeof(l)); - memcpy(buf + sizeof(l), &fieldnum, sizeof(fieldnum)); -} +#undef F +#undef TYPES +#undef TAGBYTES +#undef FASTDECODE_UNPACKEDFIXED +#undef FASTDECODE_PACKEDFIXED -upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena) { - upb_ExtensionRegistry* r = upb_Arena_Malloc(arena, sizeof(*r)); - if (!r) return NULL; - r->arena = arena; - if (!upb_strtable_init(&r->exts, 8, arena)) return NULL; - return r; -} +/* string fields **************************************************************/ -bool _upb_extreg_add(upb_ExtensionRegistry* r, - const upb_MiniTable_Extension** e, size_t count) { - char buf[EXTREG_KEY_SIZE]; - const upb_MiniTable_Extension** start = e; - const upb_MiniTable_Extension** end = UPB_PTRADD(e, count); - for (; e < end; e++) { - const upb_MiniTable_Extension* ext = *e; - extreg_key(buf, ext->extendee, ext->field.number); - if (!upb_strtable_insert(&r->exts, buf, EXTREG_KEY_SIZE, - upb_value_constptr(ext), r->arena)) { - goto failure; - } - } - return true; +typedef const char* fastdecode_copystr_func(struct upb_Decoder* d, + const char* ptr, upb_Message* msg, + const upb_MiniTable* table, + uint64_t hasbits, + upb_StringView* dst); -failure: - /* Back out the entries previously added. */ - for (end = e, e = start; e < end; e++) { - const upb_MiniTable_Extension* ext = *e; - extreg_key(buf, ext->extendee, ext->field.number); - upb_strtable_remove2(&r->exts, buf, EXTREG_KEY_SIZE, NULL); +UPB_NOINLINE +static const char* fastdecode_verifyutf8(upb_Decoder* d, const char* ptr, + upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t data) { + upb_StringView* dst = (upb_StringView*)data; + if (!_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_BadUtf8); } - return false; + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); } -const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r, - const upb_MiniTable* l, - uint32_t num) { - char buf[EXTREG_KEY_SIZE]; - upb_value v; - extreg_key(buf, l, num); - if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, &v)) { - return upb_value_getconstptr(v); - } else { - return NULL; +#define FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, validate_utf8) \ + int size = (uint8_t)ptr[0]; /* Could plumb through hasbits. */ \ + ptr++; \ + if (size & 0x80) { \ + ptr = fastdecode_longsize(ptr, &size); \ + } \ + \ + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr))) { \ + dst->size = 0; \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + if (d->options & kUpb_DecodeOption_AliasString) { \ + dst->data = ptr; \ + dst->size = size; \ + } else { \ + char* data = upb_Arena_Malloc(&d->arena, size); \ + if (!data) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); \ + } \ + memcpy(data, ptr, size); \ + dst->data = data; \ + dst->size = size; \ + } \ + \ + ptr += size; \ + if (validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } else { \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ } -} - -/** upb/table.c ************************************************************/ -/* - * upb_table Implementation - * - * Implementation is heavily inspired by Lua's ltable.c. - */ - -#include - -/* Must be last. */ - -#define UPB_MAXARRSIZE 16 /* 64k. */ - -/* From Chromium. */ -#define ARRAY_SIZE(x) \ - ((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x]))))) - -static const double MAX_LOAD = 0.85; - -/* The minimum utilization of the array part of a mixed hash/array table. This - * is a speed/memory-usage tradeoff (though it's not straightforward because of - * cache effects). The lower this is, the more memory we'll use. */ -static const double MIN_DENSITY = 0.1; - -static bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; } +UPB_NOINLINE +static const char* fastdecode_longstring_utf8(struct upb_Decoder* d, + const char* ptr, upb_Message* msg, + intptr_t table, uint64_t hasbits, + uint64_t data) { + upb_StringView* dst = (upb_StringView*)data; + FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, true); +} -static upb_value _upb_value_val(uint64_t val) { - upb_value ret; - _upb_value_setval(&ret, val); - return ret; +UPB_NOINLINE +static const char* fastdecode_longstring_noutf8( + struct upb_Decoder* d, const char* ptr, upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t data) { + upb_StringView* dst = (upb_StringView*)data; + FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, false); } -static int log2ceil(uint64_t v) { - int ret = 0; - bool pow2 = is_pow2(v); - while (v >>= 1) ret++; - ret = pow2 ? ret : ret + 1; /* Ceiling. */ - return UPB_MIN(UPB_MAXARRSIZE, ret); +UPB_FORCEINLINE +static void fastdecode_docopy(upb_Decoder* d, const char* ptr, uint32_t size, + int copy, char* data, upb_StringView* dst) { + d->arena.head.ptr += copy; + dst->data = data; + UPB_UNPOISON_MEMORY_REGION(data, copy); + memcpy(data, ptr, copy); + UPB_POISON_MEMORY_REGION(data + size, copy - size); } -char* upb_strdup2(const char* s, size_t len, upb_Arena* a) { - size_t n; - char* p; - - /* Prevent overflow errors. */ - if (len == SIZE_MAX) return NULL; - /* Always null-terminate, even if binary data; but don't rely on the input to - * have a null-terminating byte since it may be a raw binary buffer. */ - n = len + 1; - p = upb_Arena_Malloc(a, n); - if (p) { - memcpy(p, s, len); - p[len] = 0; +#define FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + card, validate_utf8) \ + upb_StringView* dst; \ + fastdecode_arr farr; \ + int64_t size; \ + size_t arena_has; \ + size_t common_has; \ + char* buf; \ + \ + UPB_ASSERT((d->options & kUpb_DecodeOption_AliasString) == 0); \ + UPB_ASSERT(fastdecode_checktag(data, tagbytes)); \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_StringView), card); \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView)); \ + } \ + \ + size = (uint8_t)ptr[tagbytes]; \ + ptr += tagbytes + 1; \ + dst->size = size; \ + \ + buf = d->arena.head.ptr; \ + arena_has = _upb_ArenaHas(&d->arena); \ + common_has = UPB_MIN(arena_has, (d->end - ptr) + 16); \ + \ + if (UPB_LIKELY(size <= 15 - tagbytes)) { \ + if (arena_has < 16) goto longstr; \ + d->arena.head.ptr += 16; \ + memcpy(buf, ptr - tagbytes - 1, 16); \ + dst->data = buf + tagbytes + 1; \ + } else if (UPB_LIKELY(size <= 32)) { \ + if (UPB_UNLIKELY(common_has < 32)) goto longstr; \ + fastdecode_docopy(d, ptr, size, 32, buf, dst); \ + } else if (UPB_LIKELY(size <= 64)) { \ + if (UPB_UNLIKELY(common_has < 64)) goto longstr; \ + fastdecode_docopy(d, ptr, size, 64, buf, dst); \ + } else if (UPB_LIKELY(size < 128)) { \ + if (UPB_UNLIKELY(common_has < 128)) goto longstr; \ + fastdecode_docopy(d, ptr, size, 128, buf, dst); \ + } else { \ + goto longstr; \ + } \ + \ + ptr += size; \ + \ + if (card == CARD_r) { \ + if (validate_utf8 && \ + !_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_BadUtf8); \ + } \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + if (card != CARD_r && validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ + \ + longstr: \ + if (card == CARD_r) { \ + fastdecode_commitarr(dst + 1, &farr, sizeof(upb_StringView)); \ + } \ + ptr--; \ + if (validate_utf8) { \ + UPB_MUSTTAIL return fastdecode_longstring_utf8(d, ptr, msg, table, \ + hasbits, (uint64_t)dst); \ + } else { \ + UPB_MUSTTAIL return fastdecode_longstring_noutf8(d, ptr, msg, table, \ + hasbits, (uint64_t)dst); \ } - return p; -} - -/* A type to represent the lookup key of either a strtable or an inttable. */ -typedef union { - uintptr_t num; - struct { - const char* str; - size_t len; - } str; -} lookupkey_t; -static lookupkey_t strkey2(const char* str, size_t len) { - lookupkey_t k; - k.str.str = str; - k.str.len = len; - return k; -} +#define FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, card, \ + copyfunc, validate_utf8) \ + upb_StringView* dst; \ + fastdecode_arr farr; \ + int64_t size; \ + \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + RETURN_GENERIC("string field tag mismatch\n"); \ + } \ + \ + if (UPB_UNLIKELY((d->options & kUpb_DecodeOption_AliasString) == 0)) { \ + UPB_MUSTTAIL return copyfunc(UPB_PARSE_ARGS); \ + } \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_StringView), card); \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView)); \ + } \ + \ + size = (int8_t)ptr[tagbytes]; \ + ptr += tagbytes + 1; \ + dst->data = ptr; \ + dst->size = size; \ + \ + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->end))) { \ + ptr--; \ + if (validate_utf8) { \ + return fastdecode_longstring_utf8(d, ptr, msg, table, hasbits, \ + (uint64_t)dst); \ + } else { \ + return fastdecode_longstring_noutf8(d, ptr, msg, table, hasbits, \ + (uint64_t)dst); \ + } \ + } \ + \ + ptr += size; \ + \ + if (card == CARD_r) { \ + if (validate_utf8 && \ + !_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_BadUtf8); \ + } \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + if (UPB_UNLIKELY((d->options & kUpb_DecodeOption_AliasString) == 0)) { \ + /* Buffer flipped and we can't alias any more. Bounce to */ \ + /* copyfunc(), but via dispatch since we need to reload table */ \ + /* data also. */ \ + fastdecode_commitarr(dst, &farr, sizeof(upb_StringView)); \ + data = ret.tag; \ + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + } \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + if (card != CARD_r && validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); -static lookupkey_t intkey(uintptr_t key) { - lookupkey_t k; - k.num = key; - return k; -} +/* Generate all combinations: + * {p,c} x {s,o,r} x {s, b} x {1bt,2bt} */ -typedef uint32_t hashfunc_t(upb_tabkey key); -typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2); +#define s_VALIDATE true +#define b_VALIDATE false -/* Base table (shared code) ***************************************************/ +#define F(card, tagbytes, type) \ + UPB_NOINLINE \ + const char* upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + CARD_##card, type##_VALIDATE); \ + } \ + const char* upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + CARD_##card, upb_c##card##type##_##tagbytes##bt, \ + type##_VALIDATE); \ + } -static uint32_t upb_inthash(uintptr_t key) { return (uint32_t)key; } +#define UTF8(card, tagbytes) \ + F(card, tagbytes, s) \ + F(card, tagbytes, b) -static const upb_tabent* upb_getentry(const upb_table* t, uint32_t hash) { - return t->entries + (hash & t->mask); -} +#define TAGBYTES(card) \ + UTF8(card, 1) \ + UTF8(card, 2) -static bool upb_arrhas(upb_tabval key) { return key.val != (uint64_t)-1; } +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) -static bool isfull(upb_table* t) { return t->count == t->max_count; } +#undef s_VALIDATE +#undef b_VALIDATE +#undef F +#undef TAGBYTES +#undef FASTDECODE_LONGSTRING +#undef FASTDECODE_COPYSTRING +#undef FASTDECODE_STRING -static bool init(upb_table* t, uint8_t size_lg2, upb_Arena* a) { - size_t bytes; +/* message fields *************************************************************/ - t->count = 0; - t->size_lg2 = size_lg2; - t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0; - t->max_count = upb_table_size(t) * MAX_LOAD; - bytes = upb_table_size(t) * sizeof(upb_tabent); - if (bytes > 0) { - t->entries = upb_Arena_Malloc(a, bytes); - if (!t->entries) return false; - memset(t->entries, 0, bytes); +UPB_INLINE +upb_Message* decode_newmsg_ceil(upb_Decoder* d, const upb_MiniTable* l, + int msg_ceil_bytes) { + size_t size = l->size + sizeof(upb_Message_Internal); + char* msg_data; + if (UPB_LIKELY(msg_ceil_bytes > 0 && + _upb_ArenaHas(&d->arena) >= msg_ceil_bytes)) { + UPB_ASSERT(size <= (size_t)msg_ceil_bytes); + msg_data = d->arena.head.ptr; + d->arena.head.ptr += size; + UPB_UNPOISON_MEMORY_REGION(msg_data, msg_ceil_bytes); + memset(msg_data, 0, msg_ceil_bytes); + UPB_POISON_MEMORY_REGION(msg_data + size, msg_ceil_bytes - size); } else { - t->entries = NULL; + msg_data = (char*)upb_Arena_Malloc(&d->arena, size); + memset(msg_data, 0, size); } - return true; + return msg_data + sizeof(upb_Message_Internal); } -static upb_tabent* emptyent(upb_table* t, upb_tabent* e) { - upb_tabent* begin = t->entries; - upb_tabent* end = begin + upb_table_size(t); - for (e = e + 1; e < end; e++) { - if (upb_tabent_isempty(e)) return e; - } - for (e = begin; e < end; e++) { - if (upb_tabent_isempty(e)) return e; - } - UPB_ASSERT(false); - return NULL; -} +typedef struct { + intptr_t table; + upb_Message* msg; +} fastdecode_submsgdata; -static upb_tabent* getentry_mutable(upb_table* t, uint32_t hash) { - return (upb_tabent*)upb_getentry(t, hash); +UPB_FORCEINLINE +static const char* fastdecode_tosubmsg(upb_Decoder* d, const char* ptr, + void* ctx) { + fastdecode_submsgdata* submsg = ctx; + ptr = fastdecode_dispatch(d, ptr, submsg->msg, submsg->table, 0, 0); + UPB_ASSUME(ptr != NULL); + return ptr; } -static const upb_tabent* findentry(const upb_table* t, lookupkey_t key, - uint32_t hash, eqlfunc_t* eql) { - const upb_tabent* e; +#define FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, \ + msg_ceil_bytes, card) \ + \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + RETURN_GENERIC("submessage field tag mismatch\n"); \ + } \ + \ + if (--d->depth == 0) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_MaxDepthExceeded); \ + } \ + \ + upb_Message** dst; \ + uint32_t submsg_idx = (data >> 16) & 0xff; \ + const upb_MiniTable* tablep = decode_totablep(table); \ + const upb_MiniTable* subtablep = tablep->subs[submsg_idx].submsg; \ + fastdecode_submsgdata submsg = {decode_totable(subtablep)}; \ + fastdecode_arr farr; \ + \ + if (subtablep->table_mask == (uint8_t)-1) { \ + RETURN_GENERIC("submessage doesn't have fast tables."); \ + } \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_Message*), card); \ + \ + if (card == CARD_s) { \ + *(uint32_t*)msg |= hasbits; \ + hasbits = 0; \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_Message*)); \ + } \ + \ + submsg.msg = *dst; \ + \ + if (card == CARD_r || UPB_LIKELY(!submsg.msg)) { \ + *dst = submsg.msg = decode_newmsg_ceil(d, subtablep, msg_ceil_bytes); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_delimited(d, ptr, fastdecode_tosubmsg, &submsg); \ + \ + if (UPB_UNLIKELY(ptr == NULL || d->end_group != DECODE_NOGROUP)) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_Message*)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + d->depth++; \ + data = ret.tag; \ + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + d->depth++; \ + return ptr; \ + } \ + } \ + \ + d->depth++; \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); - if (t->size_lg2 == 0) return NULL; - e = upb_getentry(t, hash); - if (upb_tabent_isempty(e)) return NULL; - while (1) { - if (eql(e->key, key)) return e; - if ((e = e->next) == NULL) return NULL; +#define F(card, tagbytes, size_ceil, ceil_arg) \ + const char* upb_p##card##m_##tagbytes##bt_max##size_ceil##b( \ + UPB_PARSE_PARAMS) { \ + FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, ceil_arg, \ + CARD_##card); \ } -} -static upb_tabent* findentry_mutable(upb_table* t, lookupkey_t key, - uint32_t hash, eqlfunc_t* eql) { - return (upb_tabent*)findentry(t, key, hash, eql); -} +#define SIZES(card, tagbytes) \ + F(card, tagbytes, 64, 64) \ + F(card, tagbytes, 128, 128) \ + F(card, tagbytes, 192, 192) \ + F(card, tagbytes, 256, 256) \ + F(card, tagbytes, max, -1) -static bool lookup(const upb_table* t, lookupkey_t key, upb_value* v, - uint32_t hash, eqlfunc_t* eql) { - const upb_tabent* e = findentry(t, key, hash, eql); - if (e) { - if (v) { - _upb_value_setval(v, e->val.val); - } - return true; - } else { - return false; - } -} +#define TAGBYTES(card) \ + SIZES(card, 1) \ + SIZES(card, 2) -/* The given key must not already exist in the table. */ -static void insert(upb_table* t, lookupkey_t key, upb_tabkey tabkey, - upb_value val, uint32_t hash, hashfunc_t* hashfunc, - eqlfunc_t* eql) { - upb_tabent* mainpos_e; - upb_tabent* our_e; +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) - UPB_ASSERT(findentry(t, key, hash, eql) == NULL); +#undef TAGBYTES +#undef SIZES +#undef F +#undef FASTDECODE_SUBMSG - t->count++; - mainpos_e = getentry_mutable(t, hash); - our_e = mainpos_e; +#endif /* UPB_FASTTABLE */ - if (upb_tabent_isempty(mainpos_e)) { - /* Our main position is empty; use it. */ - our_e->next = NULL; - } else { - /* Collision. */ - upb_tabent* new_e = emptyent(t, mainpos_e); - /* Head of collider's chain. */ - upb_tabent* chain = getentry_mutable(t, hashfunc(mainpos_e->key)); - if (chain == mainpos_e) { - /* Existing ent is in its main position (it has the same hash as us, and - * is the head of our chain). Insert to new ent and append to this chain. - */ - new_e->next = mainpos_e->next; - mainpos_e->next = new_e; - our_e = new_e; - } else { - /* Existing ent is not in its main position (it is a node in some other - * chain). This implies that no existing ent in the table has our hash. - * Evict it (updating its chain) and use its ent for head of our chain. */ - *new_e = *mainpos_e; /* copies next. */ - while (chain->next != mainpos_e) { - chain = (upb_tabent*)chain->next; - UPB_ASSERT(chain); - } - chain->next = new_e; - our_e = mainpos_e; - our_e->next = NULL; - } - } - our_e->key = tabkey; - our_e->val.val = val.val; - UPB_ASSERT(findentry(t, key, hash, eql) == our_e); -} -static bool rm(upb_table* t, lookupkey_t key, upb_value* val, - upb_tabkey* removed, uint32_t hash, eqlfunc_t* eql) { - upb_tabent* chain = getentry_mutable(t, hash); - if (upb_tabent_isempty(chain)) return false; - if (eql(chain->key, key)) { - /* Element to remove is at the head of its chain. */ - t->count--; - if (val) _upb_value_setval(val, chain->val.val); - if (removed) *removed = chain->key; - if (chain->next) { - upb_tabent* move = (upb_tabent*)chain->next; - *chain = *move; - move->key = 0; /* Make the slot empty. */ - } else { - chain->key = 0; /* Make the slot empty. */ - } - return true; - } else { - /* Element to remove is either in a non-head position or not in the - * table. */ - while (chain->next && !eql(chain->next->key, key)) { - chain = (upb_tabent*)chain->next; - } - if (chain->next) { - /* Found element to remove. */ - upb_tabent* rm = (upb_tabent*)chain->next; - t->count--; - if (val) _upb_value_setval(val, chain->next->val.val); - if (removed) *removed = rm->key; - rm->key = 0; /* Make the slot empty. */ - chain->next = rm->next; - return true; - } else { - /* Element to remove is not in the table. */ - return false; - } - } -} +#include +#include +#include +#include +#include +#include +#include -static size_t next(const upb_table* t, size_t i) { - do { - if (++i >= upb_table_size(t)) return SIZE_MAX - 1; /* Distinct from -1. */ - } while (upb_tabent_isempty(&t->entries[i])); - return i; -} +// Must be last. -static size_t begin(const upb_table* t) { return next(t, -1); } +typedef struct { + const char *ptr, *end; + upb_Arena* arena; /* TODO: should we have a tmp arena for tmp data? */ + const upb_DefPool* symtab; + int depth; + upb_Status* status; + jmp_buf err; + int line; + const char* line_begin; + bool is_first; + int options; + const upb_FieldDef* debug_field; +} jsondec; -/* upb_strtable ***************************************************************/ +enum { JD_OBJECT, JD_ARRAY, JD_STRING, JD_NUMBER, JD_TRUE, JD_FALSE, JD_NULL }; -/* A simple "subclass" of upb_table that only adds a hash function for strings. - */ +/* Forward declarations of mutually-recursive functions. */ +static void jsondec_wellknown(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); +static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f); +static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); +static void jsondec_object(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); -static upb_tabkey strcopy(lookupkey_t k2, upb_Arena* a) { - uint32_t len = (uint32_t)k2.str.len; - char* str = upb_Arena_Malloc(a, k2.str.len + sizeof(uint32_t) + 1); - if (str == NULL) return 0; - memcpy(str, &len, sizeof(uint32_t)); - if (k2.str.len) memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len); - str[sizeof(uint32_t) + k2.str.len] = '\0'; - return (uintptr_t)str; +static bool jsondec_streql(upb_StringView str, const char* lit) { + return str.size == strlen(lit) && memcmp(str.data, lit, str.size) == 0; } -/* Adapted from ABSL's wyhash. */ - -static uint64_t UnalignedLoad64(const void* p) { - uint64_t val; - memcpy(&val, p, 8); - return val; +static bool jsondec_isnullvalue(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Enum && + strcmp(upb_EnumDef_FullName(upb_FieldDef_EnumSubDef(f)), + "google.protobuf.NullValue") == 0; } -static uint32_t UnalignedLoad32(const void* p) { - uint32_t val; - memcpy(&val, p, 4); - return val; +static bool jsondec_isvalue(const upb_FieldDef* f) { + return (upb_FieldDef_CType(f) == kUpb_CType_Message && + upb_MessageDef_WellKnownType(upb_FieldDef_MessageSubDef(f)) == + kUpb_WellKnown_Value) || + jsondec_isnullvalue(f); } -#if defined(_MSC_VER) && defined(_M_X64) -#include -#endif - -/* Computes a * b, returning the low 64 bits of the result and storing the high - * 64 bits in |*high|. */ -static uint64_t upb_umul128(uint64_t v0, uint64_t v1, uint64_t* out_high) { -#ifdef __SIZEOF_INT128__ - __uint128_t p = v0; - p *= v1; - *out_high = (uint64_t)(p >> 64); - return (uint64_t)p; -#elif defined(_MSC_VER) && defined(_M_X64) - return _umul128(v0, v1, out_high); -#else - uint64_t a32 = v0 >> 32; - uint64_t a00 = v0 & 0xffffffff; - uint64_t b32 = v1 >> 32; - uint64_t b00 = v1 & 0xffffffff; - uint64_t high = a32 * b32; - uint64_t low = a00 * b00; - uint64_t mid1 = a32 * b00; - uint64_t mid2 = a00 * b32; - low += (mid1 << 32) + (mid2 << 32); - // Omit carry bit, for mixing we do not care about exact numerical precision. - high += (mid1 >> 32) + (mid2 >> 32); - *out_high = high; - return low; -#endif +UPB_NORETURN static void jsondec_err(jsondec* d, const char* msg) { + upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: %s", d->line, + (int)(d->ptr - d->line_begin), msg); + UPB_LONGJMP(d->err, 1); } -static uint64_t WyhashMix(uint64_t v0, uint64_t v1) { - uint64_t high; - uint64_t low = upb_umul128(v0, v1, &high); - return low ^ high; +UPB_PRINTF(2, 3) +UPB_NORETURN static void jsondec_errf(jsondec* d, const char* fmt, ...) { + va_list argp; + upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: ", d->line, + (int)(d->ptr - d->line_begin)); + va_start(argp, fmt); + upb_Status_VAppendErrorFormat(d->status, fmt, argp); + va_end(argp); + UPB_LONGJMP(d->err, 1); } -static uint64_t Wyhash(const void* data, size_t len, uint64_t seed, - const uint64_t salt[]) { - const uint8_t* ptr = (const uint8_t*)data; - uint64_t starting_length = (uint64_t)len; - uint64_t current_state = seed ^ salt[0]; +static void jsondec_skipws(jsondec* d) { + while (d->ptr != d->end) { + switch (*d->ptr) { + case '\n': + d->line++; + d->line_begin = d->ptr; + /* Fallthrough. */ + case '\r': + case '\t': + case ' ': + d->ptr++; + break; + default: + return; + } + } + jsondec_err(d, "Unexpected EOF"); +} - if (len > 64) { - // If we have more than 64 bytes, we're going to handle chunks of 64 - // bytes at a time. We're going to build up two separate hash states - // which we will then hash together. - uint64_t duplicated_state = current_state; +static bool jsondec_tryparsech(jsondec* d, char ch) { + if (d->ptr == d->end || *d->ptr != ch) return false; + d->ptr++; + return true; +} - do { - uint64_t a = UnalignedLoad64(ptr); - uint64_t b = UnalignedLoad64(ptr + 8); - uint64_t c = UnalignedLoad64(ptr + 16); - uint64_t d = UnalignedLoad64(ptr + 24); - uint64_t e = UnalignedLoad64(ptr + 32); - uint64_t f = UnalignedLoad64(ptr + 40); - uint64_t g = UnalignedLoad64(ptr + 48); - uint64_t h = UnalignedLoad64(ptr + 56); +static void jsondec_parselit(jsondec* d, const char* lit) { + size_t avail = d->end - d->ptr; + size_t len = strlen(lit); + if (avail < len || memcmp(d->ptr, lit, len) != 0) { + jsondec_errf(d, "Expected: '%s'", lit); + } + d->ptr += len; +} - uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state); - uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state); - current_state = (cs0 ^ cs1); +static void jsondec_wsch(jsondec* d, char ch) { + jsondec_skipws(d); + if (!jsondec_tryparsech(d, ch)) { + jsondec_errf(d, "Expected: '%c'", ch); + } +} - uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state); - uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state); - duplicated_state = (ds0 ^ ds1); +static void jsondec_true(jsondec* d) { jsondec_parselit(d, "true"); } +static void jsondec_false(jsondec* d) { jsondec_parselit(d, "false"); } +static void jsondec_null(jsondec* d) { jsondec_parselit(d, "null"); } - ptr += 64; - len -= 64; - } while (len > 64); +static void jsondec_entrysep(jsondec* d) { + jsondec_skipws(d); + jsondec_parselit(d, ":"); +} - current_state = current_state ^ duplicated_state; +static int jsondec_rawpeek(jsondec* d) { + switch (*d->ptr) { + case '{': + return JD_OBJECT; + case '[': + return JD_ARRAY; + case '"': + return JD_STRING; + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return JD_NUMBER; + case 't': + return JD_TRUE; + case 'f': + return JD_FALSE; + case 'n': + return JD_NULL; + default: + jsondec_errf(d, "Unexpected character: '%c'", *d->ptr); } +} - // We now have a data `ptr` with at most 64 bytes and the current state - // of the hashing state machine stored in current_state. - while (len > 16) { - uint64_t a = UnalignedLoad64(ptr); - uint64_t b = UnalignedLoad64(ptr + 8); +/* JSON object/array **********************************************************/ - current_state = WyhashMix(a ^ salt[1], b ^ current_state); +/* These are used like so: + * + * jsondec_objstart(d); + * while (jsondec_objnext(d)) { + * ... + * } + * jsondec_objend(d) */ - ptr += 16; - len -= 16; - } +static int jsondec_peek(jsondec* d) { + jsondec_skipws(d); + return jsondec_rawpeek(d); +} - // We now have a data `ptr` with at most 16 bytes. - uint64_t a = 0; - uint64_t b = 0; - if (len > 8) { - // When we have at least 9 and at most 16 bytes, set A to the first 64 - // bits of the input and B to the last 64 bits of the input. Yes, they will - // overlap in the middle if we are working with less than the full 16 - // bytes. - a = UnalignedLoad64(ptr); - b = UnalignedLoad64(ptr + len - 8); - } else if (len > 3) { - // If we have at least 4 and at most 8 bytes, set A to the first 32 - // bits and B to the last 32 bits. - a = UnalignedLoad32(ptr); - b = UnalignedLoad32(ptr + len - 4); - } else if (len > 0) { - // If we have at least 1 and at most 3 bytes, read all of the provided - // bits into A, with some adjustments. - a = ((ptr[0] << 16) | (ptr[len >> 1] << 8) | ptr[len - 1]); - b = 0; - } else { - a = 0; - b = 0; +static void jsondec_push(jsondec* d) { + if (--d->depth < 0) { + jsondec_err(d, "Recursion limit exceeded"); } - - uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state); - uint64_t z = salt[1] ^ starting_length; - return WyhashMix(w, z); + d->is_first = true; } -const uint64_t kWyhashSalt[5] = { - 0x243F6A8885A308D3ULL, 0x13198A2E03707344ULL, 0xA4093822299F31D0ULL, - 0x082EFA98EC4E6C89ULL, 0x452821E638D01377ULL, -}; - -uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed) { - return Wyhash(p, n, seed, kWyhashSalt); +static bool jsondec_seqnext(jsondec* d, char end_ch) { + bool is_first = d->is_first; + d->is_first = false; + jsondec_skipws(d); + if (*d->ptr == end_ch) return false; + if (!is_first) jsondec_parselit(d, ","); + return true; } -static uint32_t _upb_Hash_NoSeed(const char* p, size_t n) { - return _upb_Hash(p, n, 0); +static void jsondec_arrstart(jsondec* d) { + jsondec_push(d); + jsondec_wsch(d, '['); } -static uint32_t strhash(upb_tabkey key) { - uint32_t len; - char* str = upb_tabstr(key, &len); - return _upb_Hash_NoSeed(str, len); +static void jsondec_arrend(jsondec* d) { + d->depth++; + jsondec_wsch(d, ']'); } -static bool streql(upb_tabkey k1, lookupkey_t k2) { - uint32_t len; - char* str = upb_tabstr(k1, &len); - return len == k2.str.len && (len == 0 || memcmp(str, k2.str.str, len) == 0); -} +static bool jsondec_arrnext(jsondec* d) { return jsondec_seqnext(d, ']'); } -bool upb_strtable_init(upb_strtable* t, size_t expected_size, upb_Arena* a) { - // Multiply by approximate reciprocal of MAX_LOAD (0.85), with pow2 - // denominator. - size_t need_entries = (expected_size + 1) * 1204 / 1024; - UPB_ASSERT(need_entries >= expected_size * 0.85); - int size_lg2 = _upb_Log2Ceiling(need_entries); - return init(&t->t, size_lg2, a); +static void jsondec_objstart(jsondec* d) { + jsondec_push(d); + jsondec_wsch(d, '{'); } -void upb_strtable_clear(upb_strtable* t) { - size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent); - t->t.count = 0; - memset((char*)t->t.entries, 0, bytes); +static void jsondec_objend(jsondec* d) { + d->depth++; + jsondec_wsch(d, '}'); } -bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a) { - upb_strtable new_table; - upb_strtable_iter i; - - if (!init(&new_table.t, size_lg2, a)) return false; - upb_strtable_begin(&i, t); - for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { - upb_StringView key = upb_strtable_iter_key(&i); - upb_strtable_insert(&new_table, key.data, key.size, - upb_strtable_iter_value(&i), a); +static bool jsondec_objnext(jsondec* d) { + if (!jsondec_seqnext(d, '}')) return false; + if (jsondec_peek(d) != JD_STRING) { + jsondec_err(d, "Object must start with string"); } - *t = new_table; return true; } -bool upb_strtable_insert(upb_strtable* t, const char* k, size_t len, - upb_value v, upb_Arena* a) { - lookupkey_t key; - upb_tabkey tabkey; - uint32_t hash; +/* JSON number ****************************************************************/ - if (isfull(&t->t)) { - /* Need to resize. New table of double the size, add old elements to it. */ - if (!upb_strtable_resize(t, t->t.size_lg2 + 1, a)) { - return false; +static bool jsondec_tryskipdigits(jsondec* d) { + const char* start = d->ptr; + + while (d->ptr < d->end) { + if (*d->ptr < '0' || *d->ptr > '9') { + break; } + d->ptr++; } - key = strkey2(k, len); - tabkey = strcopy(key, a); - if (tabkey == 0) return false; - - hash = _upb_Hash_NoSeed(key.str.str, key.str.len); - insert(&t->t, key, tabkey, v, hash, &strhash, &streql); - return true; + return d->ptr != start; } -bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, - upb_value* v) { - uint32_t hash = _upb_Hash_NoSeed(key, len); - return lookup(&t->t, strkey2(key, len), v, hash, &streql); +static void jsondec_skipdigits(jsondec* d) { + if (!jsondec_tryskipdigits(d)) { + jsondec_err(d, "Expected one or more digits"); + } } -bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, - upb_value* val) { - uint32_t hash = _upb_Hash_NoSeed(key, len); - upb_tabkey tabkey; - return rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql); -} +static double jsondec_number(jsondec* d) { + const char* start = d->ptr; -/* Iteration */ + assert(jsondec_rawpeek(d) == JD_NUMBER); -void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t) { - i->t = t; - i->index = begin(&t->t); -} + /* Skip over the syntax of a number, as specified by JSON. */ + if (*d->ptr == '-') d->ptr++; -void upb_strtable_next(upb_strtable_iter* i) { - i->index = next(&i->t->t, i->index); -} + if (jsondec_tryparsech(d, '0')) { + if (jsondec_tryskipdigits(d)) { + jsondec_err(d, "number cannot have leading zero"); + } + } else { + jsondec_skipdigits(d); + } -bool upb_strtable_done(const upb_strtable_iter* i) { - if (!i->t) return true; - return i->index >= upb_table_size(&i->t->t) || - upb_tabent_isempty(str_tabent(i)); -} + if (d->ptr == d->end) goto parse; + if (jsondec_tryparsech(d, '.')) { + jsondec_skipdigits(d); + } + if (d->ptr == d->end) goto parse; -upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i) { - upb_StringView key; - uint32_t len; - UPB_ASSERT(!upb_strtable_done(i)); - key.data = upb_tabstr(str_tabent(i)->key, &len); - key.size = len; - return key; -} + if (*d->ptr == 'e' || *d->ptr == 'E') { + d->ptr++; + if (d->ptr == d->end) { + jsondec_err(d, "Unexpected EOF in number"); + } + if (*d->ptr == '+' || *d->ptr == '-') { + d->ptr++; + } + jsondec_skipdigits(d); + } -upb_value upb_strtable_iter_value(const upb_strtable_iter* i) { - UPB_ASSERT(!upb_strtable_done(i)); - return _upb_value_val(str_tabent(i)->val.val); -} +parse: + /* Having verified the syntax of a JSON number, use strtod() to parse + * (strtod() accepts a superset of JSON syntax). */ + errno = 0; + { + char* end; + double val = strtod(start, &end); + assert(end == d->ptr); -void upb_strtable_iter_setdone(upb_strtable_iter* i) { - i->t = NULL; - i->index = SIZE_MAX; -} + /* Currently the min/max-val conformance tests fail if we check this. Does + * this mean the conformance tests are wrong or strtod() is wrong, or + * something else? Investigate further. */ + /* + if (errno == ERANGE) { + jsondec_err(d, "Number out of range"); + } + */ -bool upb_strtable_iter_isequal(const upb_strtable_iter* i1, - const upb_strtable_iter* i2) { - if (upb_strtable_done(i1) && upb_strtable_done(i2)) return true; - return i1->t == i2->t && i1->index == i2->index; + if (val > DBL_MAX || val < -DBL_MAX) { + jsondec_err(d, "Number out of range"); + } + + return val; + } } -/* upb_inttable ***************************************************************/ +/* JSON string ****************************************************************/ -/* For inttables we use a hybrid structure where small keys are kept in an - * array and large keys are put in the hash table. */ +static char jsondec_escape(jsondec* d) { + switch (*d->ptr++) { + case '"': + return '\"'; + case '\\': + return '\\'; + case '/': + return '/'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + default: + jsondec_err(d, "Invalid escape char"); + } +} -static uint32_t inthash(upb_tabkey key) { return upb_inthash(key); } +static uint32_t jsondec_codepoint(jsondec* d) { + uint32_t cp = 0; + const char* end; -static bool inteql(upb_tabkey k1, lookupkey_t k2) { return k1 == k2.num; } + if (d->end - d->ptr < 4) { + jsondec_err(d, "EOF inside string"); + } -static upb_tabval* mutable_array(upb_inttable* t) { - return (upb_tabval*)t->array; + end = d->ptr + 4; + while (d->ptr < end) { + char ch = *d->ptr++; + if (ch >= '0' && ch <= '9') { + ch -= '0'; + } else if (ch >= 'a' && ch <= 'f') { + ch = ch - 'a' + 10; + } else if (ch >= 'A' && ch <= 'F') { + ch = ch - 'A' + 10; + } else { + jsondec_err(d, "Invalid hex digit"); + } + cp = (cp << 4) | ch; + } + + return cp; } -static upb_tabval* inttable_val(upb_inttable* t, uintptr_t key) { - if (key < t->array_size) { - return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL; - } else { - upb_tabent* e = - findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql); - return e ? &e->val : NULL; +/* Parses a \uXXXX unicode escape (possibly a surrogate pair). */ +static size_t jsondec_unicode(jsondec* d, char* out) { + uint32_t cp = jsondec_codepoint(d); + if (upb_Unicode_IsHigh(cp)) { + /* Surrogate pair: two 16-bit codepoints become a 32-bit codepoint. */ + jsondec_parselit(d, "\\u"); + uint32_t low = jsondec_codepoint(d); + if (!upb_Unicode_IsLow(low)) jsondec_err(d, "Invalid low surrogate"); + cp = upb_Unicode_FromPair(cp, low); + } else if (upb_Unicode_IsLow(cp)) { + jsondec_err(d, "Unpaired low surrogate"); } -} -static const upb_tabval* inttable_val_const(const upb_inttable* t, - uintptr_t key) { - return inttable_val((upb_inttable*)t, key); + /* Write to UTF-8 */ + int bytes = upb_Unicode_ToUTF8(cp, out); + if (bytes == 0) jsondec_err(d, "Invalid codepoint"); + return bytes; } -size_t upb_inttable_count(const upb_inttable* t) { - return t->t.count + t->array_count; -} +static void jsondec_resize(jsondec* d, char** buf, char** end, char** buf_end) { + size_t oldsize = *buf_end - *buf; + size_t len = *end - *buf; + size_t size = UPB_MAX(8, 2 * oldsize); -static void check(upb_inttable* t) { - UPB_UNUSED(t); -#if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG) - { - /* This check is very expensive (makes inserts/deletes O(N)). */ - size_t count = 0; - upb_inttable_iter i; - upb_inttable_begin(&i, t); - for (; !upb_inttable_done(&i); upb_inttable_next(&i), count++) { - UPB_ASSERT(upb_inttable_lookup(t, upb_inttable_iter_key(&i), NULL)); - } - UPB_ASSERT(count == upb_inttable_count(t)); - } -#endif + *buf = upb_Arena_Realloc(d->arena, *buf, len, size); + if (!*buf) jsondec_err(d, "Out of memory"); + + *end = *buf + len; + *buf_end = *buf + size; } -bool upb_inttable_sizedinit(upb_inttable* t, size_t asize, int hsize_lg2, - upb_Arena* a) { - size_t array_bytes; - - if (!init(&t->t, hsize_lg2, a)) return false; - /* Always make the array part at least 1 long, so that we know key 0 - * won't be in the hash part, which simplifies things. */ - t->array_size = UPB_MAX(1, asize); - t->array_count = 0; - array_bytes = t->array_size * sizeof(upb_value); - t->array = upb_Arena_Malloc(a, array_bytes); - if (!t->array) { - return false; - } - memset(mutable_array(t), 0xff, array_bytes); - check(t); - return true; -} - -bool upb_inttable_init(upb_inttable* t, upb_Arena* a) { - return upb_inttable_sizedinit(t, 0, 4, a); -} +static upb_StringView jsondec_string(jsondec* d) { + char* buf = NULL; + char* end = NULL; + char* buf_end = NULL; -bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, - upb_Arena* a) { - upb_tabval tabval; - tabval.val = val.val; - UPB_ASSERT( - upb_arrhas(tabval)); /* This will reject (uint64_t)-1. Fix this. */ + jsondec_skipws(d); - if (key < t->array_size) { - UPB_ASSERT(!upb_arrhas(t->array[key])); - t->array_count++; - mutable_array(t)[key].val = val.val; - } else { - if (isfull(&t->t)) { - /* Need to resize the hash part, but we re-use the array part. */ - size_t i; - upb_table new_table; + if (*d->ptr++ != '"') { + jsondec_err(d, "Expected string"); + } - if (!init(&new_table, t->t.size_lg2 + 1, a)) { - return false; - } + while (d->ptr < d->end) { + char ch = *d->ptr++; - for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) { - const upb_tabent* e = &t->t.entries[i]; - uint32_t hash; - upb_value v; + if (end == buf_end) { + jsondec_resize(d, &buf, &end, &buf_end); + } - _upb_value_setval(&v, e->val.val); - hash = upb_inthash(e->key); - insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql); + switch (ch) { + case '"': { + upb_StringView ret; + ret.data = buf; + ret.size = end - buf; + *end = '\0'; /* Needed for possible strtod(). */ + return ret; } - - UPB_ASSERT(t->t.count == new_table.count); - - t->t = new_table; + case '\\': + if (d->ptr == d->end) goto eof; + if (*d->ptr == 'u') { + d->ptr++; + if (buf_end - end < 4) { + /* Allow space for maximum-sized codepoint (4 bytes). */ + jsondec_resize(d, &buf, &end, &buf_end); + } + end += jsondec_unicode(d, end); + } else { + *end++ = jsondec_escape(d); + } + break; + default: + if ((unsigned char)*d->ptr < 0x20) { + jsondec_err(d, "Invalid char in JSON string"); + } + *end++ = ch; + break; } - insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql); } - check(t); - return true; -} - -bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v) { - const upb_tabval* table_v = inttable_val_const(t, key); - if (!table_v) return false; - if (v) _upb_value_setval(v, table_v->val); - return true; -} -bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val) { - upb_tabval* table_v = inttable_val(t, key); - if (!table_v) return false; - table_v->val = val.val; - return true; +eof: + jsondec_err(d, "EOF inside string"); } -bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val) { - bool success; - if (key < t->array_size) { - if (upb_arrhas(t->array[key])) { - upb_tabval empty = UPB_TABVALUE_EMPTY_INIT; - t->array_count--; - if (val) { - _upb_value_setval(val, t->array[key].val); +static void jsondec_skipval(jsondec* d) { + switch (jsondec_peek(d)) { + case JD_OBJECT: + jsondec_objstart(d); + while (jsondec_objnext(d)) { + jsondec_string(d); + jsondec_entrysep(d); + jsondec_skipval(d); } - mutable_array(t)[key] = empty; - success = true; - } else { - success = false; - } - } else { - success = rm(&t->t, intkey(key), val, NULL, upb_inthash(key), &inteql); + jsondec_objend(d); + break; + case JD_ARRAY: + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + jsondec_skipval(d); + } + jsondec_arrend(d); + break; + case JD_TRUE: + jsondec_true(d); + break; + case JD_FALSE: + jsondec_false(d); + break; + case JD_NULL: + jsondec_null(d); + break; + case JD_STRING: + jsondec_string(d); + break; + case JD_NUMBER: + jsondec_number(d); + break; } - check(t); - return success; } -void upb_inttable_compact(upb_inttable* t, upb_Arena* a) { - /* A power-of-two histogram of the table keys. */ - size_t counts[UPB_MAXARRSIZE + 1] = {0}; - - /* The max key in each bucket. */ - uintptr_t max[UPB_MAXARRSIZE + 1] = {0}; +/* Base64 decoding for bytes fields. ******************************************/ - upb_inttable_iter i; - size_t arr_count; - int size_lg2; - upb_inttable new_t; +static unsigned int jsondec_base64_tablelookup(const char ch) { + /* Table includes the normal base64 chars plus the URL-safe variant. */ + const signed char table[256] = { + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, 62 /*+*/, -1, 62 /*-*/, -1, 63 /*/ */, 52 /*0*/, + 53 /*1*/, 54 /*2*/, 55 /*3*/, 56 /*4*/, 57 /*5*/, 58 /*6*/, 59 /*7*/, + 60 /*8*/, 61 /*9*/, -1, -1, -1, -1, -1, + -1, -1, 0 /*A*/, 1 /*B*/, 2 /*C*/, 3 /*D*/, 4 /*E*/, + 5 /*F*/, 6 /*G*/, 07 /*H*/, 8 /*I*/, 9 /*J*/, 10 /*K*/, 11 /*L*/, + 12 /*M*/, 13 /*N*/, 14 /*O*/, 15 /*P*/, 16 /*Q*/, 17 /*R*/, 18 /*S*/, + 19 /*T*/, 20 /*U*/, 21 /*V*/, 22 /*W*/, 23 /*X*/, 24 /*Y*/, 25 /*Z*/, + -1, -1, -1, -1, 63 /*_*/, -1, 26 /*a*/, + 27 /*b*/, 28 /*c*/, 29 /*d*/, 30 /*e*/, 31 /*f*/, 32 /*g*/, 33 /*h*/, + 34 /*i*/, 35 /*j*/, 36 /*k*/, 37 /*l*/, 38 /*m*/, 39 /*n*/, 40 /*o*/, + 41 /*p*/, 42 /*q*/, 43 /*r*/, 44 /*s*/, 45 /*t*/, 46 /*u*/, 47 /*v*/, + 48 /*w*/, 49 /*x*/, 50 /*y*/, 51 /*z*/, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1}; - upb_inttable_begin(&i, t); - for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { - uintptr_t key = upb_inttable_iter_key(&i); - int bucket = log2ceil(key); - max[bucket] = UPB_MAX(max[bucket], key); - counts[bucket]++; - } + /* Sign-extend return value so high bit will be set on any unexpected char. */ + return table[(unsigned)ch]; +} - /* Find the largest power of two that satisfies the MIN_DENSITY - * definition (while actually having some keys). */ - arr_count = upb_inttable_count(t); +static char* jsondec_partialbase64(jsondec* d, const char* ptr, const char* end, + char* out) { + int32_t val = -1; - for (size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 0; size_lg2--) { - if (counts[size_lg2] == 0) { - /* We can halve again without losing any entries. */ - continue; - } else if (arr_count >= (1 << size_lg2) * MIN_DENSITY) { + switch (end - ptr) { + case 2: + val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12; + out[0] = val >> 16; + out += 1; + break; + case 3: + val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12 | + jsondec_base64_tablelookup(ptr[2]) << 6; + out[0] = val >> 16; + out[1] = (val >> 8) & 0xff; + out += 2; break; - } - - arr_count -= counts[size_lg2]; } - UPB_ASSERT(arr_count <= upb_inttable_count(t)); + if (val < 0) { + jsondec_err(d, "Corrupt base64"); + } - { - /* Insert all elements into new, perfectly-sized table. */ - size_t arr_size = max[size_lg2] + 1; /* +1 so arr[max] will fit. */ - size_t hash_count = upb_inttable_count(t) - arr_count; - size_t hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0; - int hashsize_lg2 = log2ceil(hash_size); + return out; +} - upb_inttable_sizedinit(&new_t, arr_size, hashsize_lg2, a); - upb_inttable_begin(&i, t); - for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { - uintptr_t k = upb_inttable_iter_key(&i); - upb_inttable_insert(&new_t, k, upb_inttable_iter_value(&i), a); +static size_t jsondec_base64(jsondec* d, upb_StringView str) { + /* We decode in place. This is safe because this is a new buffer (not + * aliasing the input) and because base64 decoding shrinks 4 bytes into 3. */ + char* out = (char*)str.data; + const char* ptr = str.data; + const char* end = ptr + str.size; + const char* end4 = ptr + (str.size & -4); /* Round down to multiple of 4. */ + + for (; ptr < end4; ptr += 4, out += 3) { + int val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12 | + jsondec_base64_tablelookup(ptr[2]) << 6 | + jsondec_base64_tablelookup(ptr[3]) << 0; + + if (val < 0) { + /* Junk chars or padding. Remove trailing padding, if any. */ + if (end - ptr == 4 && ptr[3] == '=') { + if (ptr[2] == '=') { + end -= 2; + } else { + end -= 1; + } + } + break; } - UPB_ASSERT(new_t.array_size == arr_size); - UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2); + + out[0] = val >> 16; + out[1] = (val >> 8) & 0xff; + out[2] = val & 0xff; } - *t = new_t; + + if (ptr < end) { + /* Process remaining chars. We do not require padding. */ + out = jsondec_partialbase64(d, ptr, end, out); + } + + return out - str.data; } -/* Iteration. */ +/* Low-level integer parsing **************************************************/ -static const upb_tabent* int_tabent(const upb_inttable_iter* i) { - UPB_ASSERT(!i->array_part); - return &i->t->t.entries[i->index]; +static const char* jsondec_buftouint64(jsondec* d, const char* ptr, + const char* end, uint64_t* val) { + const char* out = upb_BufToUint64(ptr, end, val); + if (!out) jsondec_err(d, "Integer overflow"); + return out; } -static upb_tabval int_arrent(const upb_inttable_iter* i) { - UPB_ASSERT(i->array_part); - return i->t->array[i->index]; +static const char* jsondec_buftoint64(jsondec* d, const char* ptr, + const char* end, int64_t* val, + bool* is_neg) { + const char* out = upb_BufToInt64(ptr, end, val, is_neg); + if (!out) jsondec_err(d, "Integer overflow"); + return out; } -void upb_inttable_begin(upb_inttable_iter* i, const upb_inttable* t) { - i->t = t; - i->index = -1; - i->array_part = true; - upb_inttable_next(i); +static uint64_t jsondec_strtouint64(jsondec* d, upb_StringView str) { + const char* end = str.data + str.size; + uint64_t ret; + if (jsondec_buftouint64(d, str.data, end, &ret) != end) { + jsondec_err(d, "Non-number characters in quoted integer"); + } + return ret; } -void upb_inttable_next(upb_inttable_iter* iter) { - const upb_inttable* t = iter->t; - if (iter->array_part) { - while (++iter->index < t->array_size) { - if (upb_arrhas(int_arrent(iter))) { - return; - } - } - iter->array_part = false; - iter->index = begin(&t->t); - } else { - iter->index = next(&t->t, iter->index); +static int64_t jsondec_strtoint64(jsondec* d, upb_StringView str) { + const char* end = str.data + str.size; + int64_t ret; + if (jsondec_buftoint64(d, str.data, end, &ret, NULL) != end) { + jsondec_err(d, "Non-number characters in quoted integer"); } + return ret; } -bool upb_inttable_next2(const upb_inttable* t, uintptr_t* key, upb_value* val, - intptr_t* iter) { - intptr_t i = *iter; - if (i < t->array_size) { - while (++i < t->array_size) { - upb_tabval ent = t->array[i]; - if (upb_arrhas(ent)) { - *key = i; - *val = _upb_value_val(ent.val); - *iter = i; - return true; +/* Primitive value types ******************************************************/ + +/* Parse INT32 or INT64 value. */ +static upb_MessageValue jsondec_int(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val; + + switch (jsondec_peek(d)) { + case JD_NUMBER: { + double dbl = jsondec_number(d); + if (dbl > 9223372036854774784.0 || dbl < -9223372036854775808.0) { + jsondec_err(d, "JSON number is out of range."); + } + val.int64_val = dbl; /* must be guarded, overflow here is UB */ + if (val.int64_val != dbl) { + jsondec_errf(d, "JSON number was not integral (%f != %" PRId64 ")", dbl, + val.int64_val); } + break; + } + case JD_STRING: { + upb_StringView str = jsondec_string(d); + val.int64_val = jsondec_strtoint64(d, str); + break; } + default: + jsondec_err(d, "Expected number or string"); } - size_t tab_idx = next(&t->t, i == -1 ? -1 : i - t->array_size); - if (tab_idx < upb_table_size(&t->t)) { - upb_tabent* ent = &t->t.entries[tab_idx]; - *key = ent->key; - *val = _upb_value_val(ent->val.val); - *iter = tab_idx + t->array_size; - return true; + if (upb_FieldDef_CType(f) == kUpb_CType_Int32 || + upb_FieldDef_CType(f) == kUpb_CType_Enum) { + if (val.int64_val > INT32_MAX || val.int64_val < INT32_MIN) { + jsondec_err(d, "Integer out of range."); + } + val.int32_val = (int32_t)val.int64_val; } - return false; + return val; } -void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter) { - intptr_t i = *iter; - if (i < t->array_size) { - t->array_count--; - mutable_array(t)[i].val = -1; - } else { - upb_tabent* ent = &t->t.entries[i - t->array_size]; - upb_tabent* prev = NULL; +/* Parse UINT32 or UINT64 value. */ +static upb_MessageValue jsondec_uint(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val = {0}; - // Linear search, not great. - upb_tabent* end = &t->t.entries[upb_table_size(&t->t)]; - for (upb_tabent* e = t->t.entries; e != end; e++) { - if (e->next == ent) { - prev = e; - break; + switch (jsondec_peek(d)) { + case JD_NUMBER: { + double dbl = jsondec_number(d); + if (dbl > 18446744073709549568.0 || dbl < 0) { + jsondec_err(d, "JSON number is out of range."); + } + val.uint64_val = dbl; /* must be guarded, overflow here is UB */ + if (val.uint64_val != dbl) { + jsondec_errf(d, "JSON number was not integral (%f != %" PRIu64 ")", dbl, + val.uint64_val); } + break; } - - if (prev) { - prev->next = ent->next; + case JD_STRING: { + upb_StringView str = jsondec_string(d); + val.uint64_val = jsondec_strtouint64(d, str); + break; } - - t->t.count--; - ent->key = 0; - ent->next = NULL; + default: + jsondec_err(d, "Expected number or string"); } -} -bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key, - upb_value* val, intptr_t* iter) { - size_t tab_idx = next(&t->t, *iter); - if (tab_idx < upb_table_size(&t->t)) { - upb_tabent* ent = &t->t.entries[tab_idx]; - uint32_t len; - key->data = upb_tabstr(ent->key, &len); - key->size = len; - *val = _upb_value_val(ent->val.val); - *iter = tab_idx; - return true; + if (upb_FieldDef_CType(f) == kUpb_CType_UInt32) { + if (val.uint64_val > UINT32_MAX) { + jsondec_err(d, "Integer out of range."); + } + val.uint32_val = (uint32_t)val.uint64_val; } - return false; + return val; } -void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter) { - intptr_t i = *iter; - upb_tabent* ent = &t->t.entries[i]; - upb_tabent* prev = NULL; +/* Parse DOUBLE or FLOAT value. */ +static upb_MessageValue jsondec_double(jsondec* d, const upb_FieldDef* f) { + upb_StringView str; + upb_MessageValue val = {0}; - // Linear search, not great. - upb_tabent* end = &t->t.entries[upb_table_size(&t->t)]; - for (upb_tabent* e = t->t.entries; e != end; e++) { - if (e->next == ent) { - prev = e; + switch (jsondec_peek(d)) { + case JD_NUMBER: + val.double_val = jsondec_number(d); break; - } + case JD_STRING: + str = jsondec_string(d); + if (jsondec_streql(str, "NaN")) { + val.double_val = NAN; + } else if (jsondec_streql(str, "Infinity")) { + val.double_val = INFINITY; + } else if (jsondec_streql(str, "-Infinity")) { + val.double_val = -INFINITY; + } else { + val.double_val = strtod(str.data, NULL); + } + break; + default: + jsondec_err(d, "Expected number or string"); } - if (prev) { - prev->next = ent->next; + if (upb_FieldDef_CType(f) == kUpb_CType_Float) { + float f = val.double_val; + if (val.double_val != INFINITY && val.double_val != -INFINITY) { + if (f == INFINITY || f == -INFINITY) jsondec_err(d, "Float out of range"); + } + val.float_val = f; } - t->t.count--; - ent->key = 0; - ent->next = NULL; + return val; } -bool upb_inttable_done(const upb_inttable_iter* i) { - if (!i->t) return true; - if (i->array_part) { - return i->index >= i->t->array_size || !upb_arrhas(int_arrent(i)); - } else { - return i->index >= upb_table_size(&i->t->t) || - upb_tabent_isempty(int_tabent(i)); +/* Parse STRING or BYTES value. */ +static upb_MessageValue jsondec_strfield(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val; + val.str_val = jsondec_string(d); + if (upb_FieldDef_CType(f) == kUpb_CType_Bytes) { + val.str_val.size = jsondec_base64(d, val.str_val); } + return val; } -uintptr_t upb_inttable_iter_key(const upb_inttable_iter* i) { - UPB_ASSERT(!upb_inttable_done(i)); - return i->array_part ? i->index : int_tabent(i)->key; -} - -upb_value upb_inttable_iter_value(const upb_inttable_iter* i) { - UPB_ASSERT(!upb_inttable_done(i)); - return _upb_value_val(i->array_part ? i->t->array[i->index].val - : int_tabent(i)->val.val); -} - -void upb_inttable_iter_setdone(upb_inttable_iter* i) { - i->t = NULL; - i->index = SIZE_MAX; - i->array_part = false; -} - -bool upb_inttable_iter_isequal(const upb_inttable_iter* i1, - const upb_inttable_iter* i2) { - if (upb_inttable_done(i1) && upb_inttable_done(i2)) return true; - return i1->t == i2->t && i1->index == i2->index && - i1->array_part == i2->array_part; +static upb_MessageValue jsondec_enum(jsondec* d, const upb_FieldDef* f) { + switch (jsondec_peek(d)) { + case JD_STRING: { + upb_StringView str = jsondec_string(d); + const upb_EnumDef* e = upb_FieldDef_EnumSubDef(f); + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByNameWithSize(e, str.data, str.size); + upb_MessageValue val; + if (ev) { + val.int32_val = upb_EnumValueDef_Number(ev); + } else { + if (d->options & upb_JsonDecode_IgnoreUnknown) { + val.int32_val = 0; + } else { + jsondec_errf(d, "Unknown enumerator: '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(str)); + } + } + return val; + } + case JD_NULL: { + if (jsondec_isnullvalue(f)) { + upb_MessageValue val; + jsondec_null(d); + val.int32_val = 0; + return val; + } + } + /* Fallthrough. */ + default: + return jsondec_int(d, f); + } } -/** upb/upb.c ************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include - - -// Must be last. +static upb_MessageValue jsondec_bool(jsondec* d, const upb_FieldDef* f) { + bool is_map_key = upb_FieldDef_Number(f) == 1 && + upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f)); + upb_MessageValue val; -/* upb_Status *****************************************************************/ + if (is_map_key) { + upb_StringView str = jsondec_string(d); + if (jsondec_streql(str, "true")) { + val.bool_val = true; + } else if (jsondec_streql(str, "false")) { + val.bool_val = false; + } else { + jsondec_err(d, "Invalid boolean map key"); + } + } else { + switch (jsondec_peek(d)) { + case JD_TRUE: + val.bool_val = true; + jsondec_true(d); + break; + case JD_FALSE: + val.bool_val = false; + jsondec_false(d); + break; + default: + jsondec_err(d, "Expected true or false"); + } + } -void upb_Status_Clear(upb_Status* status) { - if (!status) return; - status->ok = true; - status->msg[0] = '\0'; + return val; } -bool upb_Status_IsOk(const upb_Status* status) { return status->ok; } - -const char* upb_Status_ErrorMessage(const upb_Status* status) { - return status->msg; -} +/* Composite types (array/message/map) ****************************************/ -void upb_Status_SetErrorMessage(upb_Status* status, const char* msg) { - if (!status) return; - status->ok = false; - strncpy(status->msg, msg, _kUpb_Status_MaxMessage - 1); - status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; -} +static void jsondec_array(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { + upb_Array* arr = upb_Message_Mutable(msg, f, d->arena).array; -void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) { - va_list args; - va_start(args, fmt); - upb_Status_VSetErrorFormat(status, fmt, args); - va_end(args); + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + upb_MessageValue elem = jsondec_value(d, f); + upb_Array_Append(arr, elem, d->arena); + } + jsondec_arrend(d); } -void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, - va_list args) { - if (!status) return; - status->ok = false; - vsnprintf(status->msg, sizeof(status->msg), fmt, args); - status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; -} +static void jsondec_map(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { + upb_Map* map = upb_Message_Mutable(msg, f, d->arena).map; + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); -void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, - va_list args) { - size_t len; - if (!status) return; - status->ok = false; - len = strlen(status->msg); - vsnprintf(status->msg + len, sizeof(status->msg) - len, fmt, args); - status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; + jsondec_objstart(d); + while (jsondec_objnext(d)) { + upb_MessageValue key, val; + key = jsondec_value(d, key_f); + jsondec_entrysep(d); + val = jsondec_value(d, val_f); + upb_Map_Set(map, key, val, d->arena); + } + jsondec_objend(d); } -/* upb_alloc ******************************************************************/ - -static void* upb_global_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize, - size_t size) { - UPB_UNUSED(alloc); - UPB_UNUSED(oldsize); - if (size == 0) { - free(ptr); - return NULL; +static void jsondec_tomsg(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { + jsondec_object(d, msg, m); } else { - return realloc(ptr, size); + jsondec_wellknown(d, msg, m); } } -static uint32_t* upb_cleanup_pointer(uintptr_t cleanup_metadata) { - return (uint32_t*)(cleanup_metadata & ~0x1); -} +static upb_MessageValue jsondec_msg(jsondec* d, const upb_FieldDef* f) { + const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); + upb_Message* msg = upb_Message_New(m, d->arena); + upb_MessageValue val; -static bool upb_cleanup_has_initial_block(uintptr_t cleanup_metadata) { - return cleanup_metadata & 0x1; + jsondec_tomsg(d, msg, m); + val.msg_val = msg; + return val; } -static uintptr_t upb_cleanup_metadata(uint32_t* cleanup, - bool has_initial_block) { - return (uintptr_t)cleanup | has_initial_block; -} +static void jsondec_field(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_StringView name; + const upb_FieldDef* f; + const upb_FieldDef* preserved; -upb_alloc upb_alloc_global = {&upb_global_allocfunc}; + name = jsondec_string(d); + jsondec_entrysep(d); -/* upb_Arena ******************************************************************/ + if (name.size >= 2 && name.data[0] == '[' && + name.data[name.size - 1] == ']') { + f = upb_DefPool_FindExtensionByNameWithSize(d->symtab, name.data + 1, + name.size - 2); + if (f && upb_FieldDef_ContainingType(f) != m) { + jsondec_errf( + d, "Extension %s extends message %s, but was seen in message %s", + upb_FieldDef_FullName(f), + upb_MessageDef_FullName(upb_FieldDef_ContainingType(f)), + upb_MessageDef_FullName(m)); + } + } else { + f = upb_MessageDef_FindByJsonNameWithSize(m, name.data, name.size); + } -/* Be conservative and choose 16 in case anyone is using SSE. */ + if (!f) { + if ((d->options & upb_JsonDecode_IgnoreUnknown) == 0) { + jsondec_errf(d, "No such field: " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(name)); + } + jsondec_skipval(d); + return; + } -struct mem_block { - struct mem_block* next; - uint32_t size; - uint32_t cleanups; - /* Data follows. */ -}; + if (jsondec_peek(d) == JD_NULL && !jsondec_isvalue(f)) { + /* JSON "null" indicates a default value, so no need to set anything. */ + jsondec_null(d); + return; + } -typedef struct cleanup_ent { - upb_CleanupFunc* cleanup; - void* ud; -} cleanup_ent; + if (upb_FieldDef_RealContainingOneof(f) && + upb_Message_WhichOneof(msg, upb_FieldDef_ContainingOneof(f))) { + jsondec_err(d, "More than one field for this oneof."); + } -static const size_t memblock_reserve = UPB_ALIGN_UP(sizeof(mem_block), 16); + preserved = d->debug_field; + d->debug_field = f; -static upb_Arena* arena_findroot(upb_Arena* a) { - /* Path splitting keeps time complexity down, see: - * https://en.wikipedia.org/wiki/Disjoint-set_data_structure */ - while (a->parent != a) { - upb_Arena* next = a->parent; - a->parent = next->parent; - a = next; + if (upb_FieldDef_IsMap(f)) { + jsondec_map(d, msg, f); + } else if (upb_FieldDef_IsRepeated(f)) { + jsondec_array(d, msg, f); + } else if (upb_FieldDef_IsSubMessage(f)) { + upb_Message* submsg = upb_Message_Mutable(msg, f, d->arena).msg; + const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); + jsondec_tomsg(d, submsg, subm); + } else { + upb_MessageValue val = jsondec_value(d, f); + upb_Message_Set(msg, f, val, d->arena); } - return a; + + d->debug_field = preserved; } -static void upb_Arena_addblock(upb_Arena* a, upb_Arena* root, void* ptr, - size_t size) { - mem_block* block = ptr; +static void jsondec_object(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + jsondec_objstart(d); + while (jsondec_objnext(d)) { + jsondec_field(d, msg, m); + } + jsondec_objend(d); +} - /* The block is for arena |a|, but should appear in the freelist of |root|. */ - block->next = root->freelist; - block->size = (uint32_t)size; - block->cleanups = 0; - root->freelist = block; - a->last_size = block->size; - if (!root->freelist_tail) root->freelist_tail = block; +static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + return jsondec_bool(d, f); + case kUpb_CType_Float: + case kUpb_CType_Double: + return jsondec_double(d, f); + case kUpb_CType_UInt32: + case kUpb_CType_UInt64: + return jsondec_uint(d, f); + case kUpb_CType_Int32: + case kUpb_CType_Int64: + return jsondec_int(d, f); + case kUpb_CType_String: + case kUpb_CType_Bytes: + return jsondec_strfield(d, f); + case kUpb_CType_Enum: + return jsondec_enum(d, f); + case kUpb_CType_Message: + return jsondec_msg(d, f); + default: + UPB_UNREACHABLE(); + } +} - a->head.ptr = UPB_PTR_AT(block, memblock_reserve, char); - a->head.end = UPB_PTR_AT(block, size, char); - a->cleanup_metadata = upb_cleanup_metadata( - &block->cleanups, upb_cleanup_has_initial_block(a->cleanup_metadata)); +/* Well-known types ***********************************************************/ - UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr); -} +static int jsondec_tsdigits(jsondec* d, const char** ptr, size_t digits, + const char* after) { + uint64_t val; + const char* p = *ptr; + const char* end = p + digits; + size_t after_len = after ? strlen(after) : 0; -static bool upb_Arena_Allocblock(upb_Arena* a, size_t size) { - upb_Arena* root = arena_findroot(a); - size_t block_size = UPB_MAX(size, a->last_size * 2) + memblock_reserve; - mem_block* block = upb_malloc(root->block_alloc, block_size); + UPB_ASSERT(digits <= 9); /* int can't overflow. */ - if (!block) return false; - upb_Arena_addblock(a, root, block, block_size); - return true; -} + if (jsondec_buftouint64(d, p, end, &val) != end || + (after_len && memcmp(end, after, after_len) != 0)) { + jsondec_err(d, "Malformed timestamp"); + } -void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size) { - if (!upb_Arena_Allocblock(a, size)) return NULL; /* Out of memory. */ - UPB_ASSERT(_upb_ArenaHas(a) >= size); - return upb_Arena_Malloc(a, size); -} + UPB_ASSERT(val < INT_MAX); -static void* upb_Arena_doalloc(upb_alloc* alloc, void* ptr, size_t oldsize, - size_t size) { - upb_Arena* a = (upb_Arena*)alloc; /* upb_alloc is initial member. */ - return upb_Arena_Realloc(a, ptr, oldsize, size); + *ptr = end + after_len; + return (int)val; } -/* Public Arena API ***********************************************************/ - -upb_Arena* arena_initslow(void* mem, size_t n, upb_alloc* alloc) { - const size_t first_block_overhead = sizeof(upb_Arena) + memblock_reserve; - upb_Arena* a; +static int jsondec_nanos(jsondec* d, const char** ptr, const char* end) { + uint64_t nanos = 0; + const char* p = *ptr; - /* We need to malloc the initial block. */ - n = first_block_overhead + 256; - if (!alloc || !(mem = upb_malloc(alloc, n))) { - return NULL; + if (p != end && *p == '.') { + const char* nano_end = jsondec_buftouint64(d, p + 1, end, &nanos); + int digits = (int)(nano_end - p - 1); + int exp_lg10 = 9 - digits; + if (digits > 9) { + jsondec_err(d, "Too many digits for partial seconds"); + } + while (exp_lg10--) nanos *= 10; + *ptr = nano_end; } - a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); - n -= sizeof(*a); + UPB_ASSERT(nanos < INT_MAX); - a->head.alloc.func = &upb_Arena_doalloc; - a->block_alloc = alloc; - a->parent = a; - a->refcount = 1; - a->freelist = NULL; - a->freelist_tail = NULL; - a->cleanup_metadata = upb_cleanup_metadata(NULL, false); + return (int)nanos; +} - upb_Arena_addblock(a, a, mem, n); +/* jsondec_epochdays(1970, 1, 1) == 1970-01-01 == 0. */ +int jsondec_epochdays(int y, int m, int d) { + const uint32_t year_base = 4800; /* Before min year, multiple of 400. */ + const uint32_t m_adj = m - 3; /* March-based month. */ + const uint32_t carry = m_adj > (uint32_t)m ? 1 : 0; + const uint32_t adjust = carry ? 12 : 0; + const uint32_t y_adj = y + year_base - carry; + const uint32_t month_days = ((m_adj + adjust) * 62719 + 769) / 2048; + const uint32_t leap_days = y_adj / 4 - y_adj / 100 + y_adj / 400; + return y_adj * 365 + leap_days + month_days + (d - 1) - 2472632; +} - return a; +static int64_t jsondec_unixtime(int y, int m, int d, int h, int min, int s) { + return (int64_t)jsondec_epochdays(y, m, d) * 86400 + h * 3600 + min * 60 + s; } -upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) { - upb_Arena* a; +static void jsondec_timestamp(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_MessageValue seconds; + upb_MessageValue nanos; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; - if (n) { - /* Align initial pointer up so that we return properly-aligned pointers. */ - void* aligned = (void*)UPB_ALIGN_UP((uintptr_t)mem, 16); - size_t delta = (uintptr_t)aligned - (uintptr_t)mem; - n = delta <= n ? n - delta : 0; - mem = aligned; - } + if (str.size < 20) goto malformed; - /* Round block size down to alignof(*a) since we will allocate the arena - * itself at the end. */ - n = UPB_ALIGN_DOWN(n, UPB_ALIGN_OF(upb_Arena)); + { + /* 1972-01-01T01:00:00 */ + int year = jsondec_tsdigits(d, &ptr, 4, "-"); + int mon = jsondec_tsdigits(d, &ptr, 2, "-"); + int day = jsondec_tsdigits(d, &ptr, 2, "T"); + int hour = jsondec_tsdigits(d, &ptr, 2, ":"); + int min = jsondec_tsdigits(d, &ptr, 2, ":"); + int sec = jsondec_tsdigits(d, &ptr, 2, NULL); - if (UPB_UNLIKELY(n < sizeof(upb_Arena))) { - return arena_initslow(mem, n, alloc); + seconds.int64_val = jsondec_unixtime(year, mon, day, hour, min, sec); } - a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); - - a->head.alloc.func = &upb_Arena_doalloc; - a->block_alloc = alloc; - a->parent = a; - a->refcount = 1; - a->last_size = UPB_MAX(128, n); - a->head.ptr = mem; - a->head.end = UPB_PTR_AT(mem, n - sizeof(*a), char); - a->freelist = NULL; - a->cleanup_metadata = upb_cleanup_metadata(NULL, true); - - return a; -} - -static void arena_dofree(upb_Arena* a) { - mem_block* block = a->freelist; - UPB_ASSERT(a->parent == a); - UPB_ASSERT(a->refcount == 0); + nanos.int32_val = jsondec_nanos(d, &ptr, end); - while (block) { - /* Load first since we are deleting block. */ - mem_block* next = block->next; + { + /* [+-]08:00 or Z */ + int ofs_hour = 0; + int ofs_min = 0; + bool neg = false; - if (block->cleanups > 0) { - cleanup_ent* end = UPB_PTR_AT(block, block->size, void); - cleanup_ent* ptr = end - block->cleanups; + if (ptr == end) goto malformed; - for (; ptr < end; ptr++) { - ptr->cleanup(ptr->ud); - } + switch (*ptr++) { + case '-': + neg = true; + /* fallthrough */ + case '+': + if ((end - ptr) != 5) goto malformed; + ofs_hour = jsondec_tsdigits(d, &ptr, 2, ":"); + ofs_min = jsondec_tsdigits(d, &ptr, 2, NULL); + ofs_min = ((ofs_hour * 60) + ofs_min) * 60; + seconds.int64_val += (neg ? ofs_min : -ofs_min); + break; + case 'Z': + if (ptr != end) goto malformed; + break; + default: + goto malformed; } + } - upb_free(a->block_alloc, block); - block = next; + if (seconds.int64_val < -62135596800) { + jsondec_err(d, "Timestamp out of range"); } -} -void upb_Arena_Free(upb_Arena* a) { - a = arena_findroot(a); - if (--a->refcount == 0) arena_dofree(a); + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, + d->arena); + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); + return; + +malformed: + jsondec_err(d, "Malformed timestamp"); } -bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func) { - cleanup_ent* ent; - uint32_t* cleanups = upb_cleanup_pointer(a->cleanup_metadata); +static void jsondec_duration(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_MessageValue seconds; + upb_MessageValue nanos; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; + const int64_t max = (uint64_t)3652500 * 86400; + bool neg = false; - if (!cleanups || _upb_ArenaHas(a) < sizeof(cleanup_ent)) { - if (!upb_Arena_Allocblock(a, 128)) return false; /* Out of memory. */ - UPB_ASSERT(_upb_ArenaHas(a) >= sizeof(cleanup_ent)); - cleanups = upb_cleanup_pointer(a->cleanup_metadata); + /* "3.000000001s", "3s", etc. */ + ptr = jsondec_buftoint64(d, ptr, end, &seconds.int64_val, &neg); + nanos.int32_val = jsondec_nanos(d, &ptr, end); + + if (end - ptr != 1 || *ptr != 's') { + jsondec_err(d, "Malformed duration"); } - a->head.end -= sizeof(cleanup_ent); - ent = (cleanup_ent*)a->head.end; - (*cleanups)++; - UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent)); + if (seconds.int64_val < -max || seconds.int64_val > max) { + jsondec_err(d, "Duration out of range"); + } - ent->cleanup = func; - ent->ud = ud; + if (neg) { + nanos.int32_val = -nanos.int32_val; + } - return true; + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, + d->arena); + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); } -bool upb_Arena_Fuse(upb_Arena* a1, upb_Arena* a2) { - upb_Arena* r1 = arena_findroot(a1); - upb_Arena* r2 = arena_findroot(a2); +static void jsondec_listvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(values_f); + upb_Array* values = upb_Message_Mutable(msg, values_f, d->arena).array; - if (r1 == r2) return true; /* Already fused. */ - - /* Do not fuse initial blocks since we cannot lifetime extend them. */ - if (upb_cleanup_has_initial_block(r1->cleanup_metadata)) return false; - if (upb_cleanup_has_initial_block(r2->cleanup_metadata)) return false; - - /* Only allow fuse with a common allocator */ - if (r1->block_alloc != r2->block_alloc) return false; - - /* We want to join the smaller tree to the larger tree. - * So swap first if they are backwards. */ - if (r1->refcount < r2->refcount) { - upb_Arena* tmp = r1; - r1 = r2; - r2 = tmp; - } - - /* r1 takes over r2's freelist and refcount. */ - r1->refcount += r2->refcount; - if (r2->freelist_tail) { - UPB_ASSERT(r2->freelist_tail->next == NULL); - r2->freelist_tail->next = r1->freelist; - r1->freelist = r2->freelist; + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + upb_Message* value_msg = upb_Message_New(value_m, d->arena); + upb_MessageValue value; + value.msg_val = value_msg; + upb_Array_Append(values, value, d->arena); + jsondec_wellknownvalue(d, value_msg, value_m); } - r2->parent = r1; - return true; + jsondec_arrend(d); } -/* Miscellaneous utilities ****************************************************/ +static void jsondec_struct(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(value_f); + upb_Map* fields = upb_Message_Mutable(msg, fields_f, d->arena).map; -static void upb_FixLocale(char* p) { - /* printf() is dependent on locales; sadly there is no easy and portable way - * to avoid this. This little post-processing step will translate 1,2 -> 1.2 - * since JSON needs the latter. Arguably a hack, but it is simple and the - * alternatives are far more complicated, platform-dependent, and/or larger - * in code size. */ - for (; *p; p++) { - if (*p == ',') *p = '.'; + jsondec_objstart(d); + while (jsondec_objnext(d)) { + upb_MessageValue key, value; + upb_Message* value_msg = upb_Message_New(value_m, d->arena); + key.str_val = jsondec_string(d); + value.msg_val = value_msg; + upb_Map_Set(fields, key, value, d->arena); + jsondec_entrysep(d); + jsondec_wellknownvalue(d, value_msg, value_m); } + jsondec_objend(d); } -void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size) { - assert(size >= kUpb_RoundTripBufferSize); - snprintf(buf, size, "%.*g", DBL_DIG, val); - if (strtod(buf, NULL) != val) { - snprintf(buf, size, "%.*g", DBL_DIG + 2, val); - assert(strtod(buf, NULL) == val); - } - upb_FixLocale(buf); -} +static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_MessageValue val; + const upb_FieldDef* f; + upb_Message* submsg; -void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size) { - assert(size >= kUpb_RoundTripBufferSize); - snprintf(buf, size, "%.*g", FLT_DIG, val); - if (strtof(buf, NULL) != val) { - snprintf(buf, size, "%.*g", FLT_DIG + 3, val); - assert(strtof(buf, NULL) == val); + switch (jsondec_peek(d)) { + case JD_NUMBER: + /* double number_value = 2; */ + f = upb_MessageDef_FindFieldByNumber(m, 2); + val.double_val = jsondec_number(d); + break; + case JD_STRING: + /* string string_value = 3; */ + f = upb_MessageDef_FindFieldByNumber(m, 3); + val.str_val = jsondec_string(d); + break; + case JD_FALSE: + /* bool bool_value = 4; */ + f = upb_MessageDef_FindFieldByNumber(m, 4); + val.bool_val = false; + jsondec_false(d); + break; + case JD_TRUE: + /* bool bool_value = 4; */ + f = upb_MessageDef_FindFieldByNumber(m, 4); + val.bool_val = true; + jsondec_true(d); + break; + case JD_NULL: + /* NullValue null_value = 1; */ + f = upb_MessageDef_FindFieldByNumber(m, 1); + val.int32_val = 0; + jsondec_null(d); + break; + /* Note: these cases return, because upb_Message_Mutable() is enough. */ + case JD_OBJECT: + /* Struct struct_value = 5; */ + f = upb_MessageDef_FindFieldByNumber(m, 5); + submsg = upb_Message_Mutable(msg, f, d->arena).msg; + jsondec_struct(d, submsg, upb_FieldDef_MessageSubDef(f)); + return; + case JD_ARRAY: + /* ListValue list_value = 6; */ + f = upb_MessageDef_FindFieldByNumber(m, 6); + submsg = upb_Message_Mutable(msg, f, d->arena).msg; + jsondec_listvalue(d, submsg, upb_FieldDef_MessageSubDef(f)); + return; + default: + UPB_UNREACHABLE(); } - upb_FixLocale(buf); -} - -/** upb/decode_fast.c ************************************************************/ -// Fast decoder: ~3x the speed of decode.c, but requires x86-64/ARM64. -// Also the table size grows by 2x. -// -// Could potentially be ported to other 64-bit archs that pass at least six -// arguments in registers and have 8 unused high bits in pointers. -// -// The overall design is to create specialized functions for every possible -// field type (eg. oneof boolean field with a 1 byte tag) and then dispatch -// to the specialized function as quickly as possible. - - -/* Must be last. */ - -#if UPB_FASTTABLE - -// The standard set of arguments passed to each parsing function. -// Thanks to x86-64 calling conventions, these will stay in registers. -#define UPB_PARSE_PARAMS \ - upb_Decoder *d, const char *ptr, upb_Message *msg, intptr_t table, \ - uint64_t hasbits, uint64_t data + upb_Message_Set(msg, f, val, d->arena); +} -#define UPB_PARSE_ARGS d, ptr, msg, table, hasbits, data +static upb_StringView jsondec_mask(jsondec* d, const char* buf, + const char* end) { + /* FieldMask fields grow due to inserted '_' characters, so we can't do the + * transform in place. */ + const char* ptr = buf; + upb_StringView ret; + char* out; -#define RETURN_GENERIC(m) \ - /* Uncomment either of these for debugging purposes. */ \ - /* fprintf(stderr, m); */ \ - /*__builtin_trap(); */ \ - return fastdecode_generic(d, ptr, msg, table, hasbits, 0); + ret.size = end - ptr; + while (ptr < end) { + ret.size += (*ptr >= 'A' && *ptr <= 'Z'); + ptr++; + } -typedef enum { - CARD_s = 0, /* Singular (optional, non-repeated) */ - CARD_o = 1, /* Oneof */ - CARD_r = 2, /* Repeated */ - CARD_p = 3 /* Packed Repeated */ -} upb_card; + out = upb_Arena_Malloc(d->arena, ret.size); + ptr = buf; + ret.data = out; -UPB_NOINLINE -static const char* fastdecode_isdonefallback(UPB_PARSE_PARAMS) { - int overrun = data; - int status; - ptr = decode_isdonefallback_inl(d, ptr, overrun, &status); - if (ptr == NULL) { - return fastdecode_err(d, status); + while (ptr < end) { + char ch = *ptr++; + if (ch >= 'A' && ch <= 'Z') { + *out++ = '_'; + *out++ = ch + 32; + } else if (ch == '_') { + jsondec_err(d, "field mask may not contain '_'"); + } else { + *out++ = ch; + } } - data = fastdecode_loadtag(ptr); - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); + + return ret; } -UPB_FORCEINLINE -static const char* fastdecode_dispatch(UPB_PARSE_PARAMS) { - if (UPB_UNLIKELY(ptr >= d->limit_ptr)) { - int overrun = ptr - d->end; - if (UPB_LIKELY(overrun == d->limit)) { - // Parse is finished. - *(uint32_t*)msg |= hasbits; // Sync hasbits. - const upb_MiniTable* l = decode_totablep(table); - return UPB_UNLIKELY(l->required_count) - ? decode_checkrequired(d, ptr, msg, l) - : ptr; +static void jsondec_fieldmask(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + /* repeated string paths = 1; */ + const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_Array* arr = upb_Message_Mutable(msg, paths_f, d->arena).array; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; + upb_MessageValue val; + + while (ptr < end) { + const char* elem_end = memchr(ptr, ',', end - ptr); + if (elem_end) { + val.str_val = jsondec_mask(d, ptr, elem_end); + ptr = elem_end + 1; } else { - data = overrun; - UPB_MUSTTAIL return fastdecode_isdonefallback(UPB_PARSE_ARGS); + val.str_val = jsondec_mask(d, ptr, end); + ptr = end; } + upb_Array_Append(arr, val, d->arena); } - - // Read two bytes of tag data (for a one-byte tag, the high byte is junk). - data = fastdecode_loadtag(ptr); - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); } -UPB_FORCEINLINE -static bool fastdecode_checktag(uint16_t data, int tagbytes) { - if (tagbytes == 1) { - return (data & 0xff) == 0; +static void jsondec_anyfield(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { + /* For regular types: {"@type": "[user type]", "f1": , "f2": } + * where f1, f2, etc. are the normal fields of this type. */ + jsondec_field(d, msg, m); } else { - return data == 0; + /* For well-known types: {"@type": "[well-known type]", "value": } + * where is whatever encoding the WKT normally uses. */ + upb_StringView str = jsondec_string(d); + jsondec_entrysep(d); + if (!jsondec_streql(str, "value")) { + jsondec_err(d, "Key for well-known type must be 'value'"); + } + jsondec_wellknown(d, msg, m); } } -UPB_FORCEINLINE -static const char* fastdecode_longsize(const char* ptr, int* size) { - int i; - UPB_ASSERT(*size & 0x80); - *size &= 0xff; - for (i = 0; i < 3; i++) { - ptr++; - size_t byte = (uint8_t)ptr[-1]; - *size += (byte - 1) << (7 + 7 * i); - if (UPB_LIKELY((byte & 0x80) == 0)) return ptr; - } - ptr++; - size_t byte = (uint8_t)ptr[-1]; - // len is limited by 2gb not 4gb, hence 8 and not 16 as normally expected - // for a 32 bit varint. - if (UPB_UNLIKELY(byte >= 8)) return NULL; - *size += (byte - 1) << 28; - return ptr; -} - -UPB_FORCEINLINE -static bool fastdecode_boundscheck(const char* ptr, size_t len, - const char* end) { - uintptr_t uptr = (uintptr_t)ptr; - uintptr_t uend = (uintptr_t)end + 16; - uintptr_t res = uptr + len; - return res < uptr || res > uend; -} - -UPB_FORCEINLINE -static bool fastdecode_boundscheck2(const char* ptr, size_t len, - const char* end) { - // This is one extra branch compared to the more normal: - // return (size_t)(end - ptr) < size; - // However it is one less computation if we are just about to use "ptr + len": - // https://godbolt.org/z/35YGPz - // In microbenchmarks this shows an overall 4% improvement. - uintptr_t uptr = (uintptr_t)ptr; - uintptr_t uend = (uintptr_t)end; - uintptr_t res = uptr + len; - return res < uptr || res > uend; -} +static const upb_MessageDef* jsondec_typeurl(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* type_m; + upb_StringView type_url = jsondec_string(d); + const char* end = type_url.data + type_url.size; + const char* ptr = end; + upb_MessageValue val; -typedef const char* fastdecode_delimfunc(upb_Decoder* d, const char* ptr, - void* ctx); + val.str_val = type_url; + upb_Message_Set(msg, type_url_f, val, d->arena); -UPB_FORCEINLINE -static const char* fastdecode_delimited(upb_Decoder* d, const char* ptr, - fastdecode_delimfunc* func, void* ctx) { - ptr++; - int len = (int8_t)ptr[-1]; - if (fastdecode_boundscheck2(ptr, len, d->limit_ptr)) { - // Slow case: Sub-message is >=128 bytes and/or exceeds the current buffer. - // If it exceeds the buffer limit, limit/limit_ptr will change during - // sub-message parsing, so we need to preserve delta, not limit. - if (UPB_UNLIKELY(len & 0x80)) { - // Size varint >1 byte (length >= 128). - ptr = fastdecode_longsize(ptr, &len); - if (!ptr) { - // Corrupt wire format: size exceeded INT_MAX. - return NULL; - } - } - if (ptr - d->end + (int)len > d->limit) { - // Corrupt wire format: invalid limit. - return NULL; - } - int delta = decode_pushlimit(d, ptr, len); - ptr = func(d, ptr, ctx); - decode_poplimit(d, ptr, delta); - } else { - // Fast case: Sub-message is <128 bytes and fits in the current buffer. - // This means we can preserve limit/limit_ptr verbatim. - const char* saved_limit_ptr = d->limit_ptr; - int saved_limit = d->limit; - d->limit_ptr = ptr + len; - d->limit = d->limit_ptr - d->end; - UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); - ptr = func(d, ptr, ctx); - d->limit_ptr = saved_limit_ptr; - d->limit = saved_limit; - UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); + /* Find message name after the last '/' */ + while (ptr > type_url.data && *--ptr != '/') { } - return ptr; -} - -/* singular, oneof, repeated field handling ***********************************/ - -typedef struct { - upb_Array* arr; - void* end; -} fastdecode_arr; -typedef enum { - FD_NEXT_ATLIMIT, - FD_NEXT_SAMEFIELD, - FD_NEXT_OTHERFIELD -} fastdecode_next; + if (ptr == type_url.data || ptr == end) { + jsondec_err(d, "Type url must have at least one '/' and non-empty host"); + } -typedef struct { - void* dst; - fastdecode_next next; - uint32_t tag; -} fastdecode_nextret; + ptr++; + type_m = upb_DefPool_FindMessageByNameWithSize(d->symtab, ptr, end - ptr); -UPB_FORCEINLINE -static void* fastdecode_resizearr(upb_Decoder* d, void* dst, - fastdecode_arr* farr, int valbytes) { - if (UPB_UNLIKELY(dst == farr->end)) { - size_t old_size = farr->arr->size; - size_t old_bytes = old_size * valbytes; - size_t new_size = old_size * 2; - size_t new_bytes = new_size * valbytes; - char* old_ptr = _upb_array_ptr(farr->arr); - char* new_ptr = upb_Arena_Realloc(&d->arena, old_ptr, old_bytes, new_bytes); - uint8_t elem_size_lg2 = __builtin_ctz(valbytes); - farr->arr->size = new_size; - farr->arr->data = _upb_array_tagptr(new_ptr, elem_size_lg2); - dst = (void*)(new_ptr + (old_size * valbytes)); - farr->end = (void*)(new_ptr + (new_size * valbytes)); + if (!type_m) { + jsondec_err(d, "Type was not found"); } - return dst; -} -UPB_FORCEINLINE -static bool fastdecode_tagmatch(uint32_t tag, uint64_t data, int tagbytes) { - if (tagbytes == 1) { - return (uint8_t)tag == (uint8_t)data; - } else { - return (uint16_t)tag == (uint16_t)data; - } + return type_m; } -UPB_FORCEINLINE -static void fastdecode_commitarr(void* dst, fastdecode_arr* farr, - int valbytes) { - farr->arr->len = - (size_t)((char*)dst - (char*)_upb_array_ptr(farr->arr)) / valbytes; -} +static void jsondec_any(jsondec* d, upb_Message* msg, const upb_MessageDef* m) { + /* string type_url = 1; + * bytes value = 2; */ + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); + upb_Message* any_msg; + const upb_MessageDef* any_m = NULL; + const char* pre_type_data = NULL; + const char* pre_type_end = NULL; + upb_MessageValue encoded; -UPB_FORCEINLINE -static fastdecode_nextret fastdecode_nextrepeated(upb_Decoder* d, void* dst, - const char** ptr, - fastdecode_arr* farr, - uint64_t data, int tagbytes, - int valbytes) { - fastdecode_nextret ret; - dst = (char*)dst + valbytes; + jsondec_objstart(d); - if (UPB_LIKELY(!decode_isdone(d, ptr))) { - ret.tag = fastdecode_loadtag(*ptr); - if (fastdecode_tagmatch(ret.tag, data, tagbytes)) { - ret.next = FD_NEXT_SAMEFIELD; + /* Scan looking for "@type", which is not necessarily first. */ + while (!any_m && jsondec_objnext(d)) { + const char* start = d->ptr; + upb_StringView name = jsondec_string(d); + jsondec_entrysep(d); + if (jsondec_streql(name, "@type")) { + any_m = jsondec_typeurl(d, msg, m); + if (pre_type_data) { + pre_type_end = start; + while (*pre_type_end != ',') pre_type_end--; + } } else { - fastdecode_commitarr(dst, farr, valbytes); - ret.next = FD_NEXT_OTHERFIELD; + if (!pre_type_data) pre_type_data = start; + jsondec_skipval(d); } - } else { - fastdecode_commitarr(dst, farr, valbytes); - ret.next = FD_NEXT_ATLIMIT; } - ret.dst = dst; - return ret; -} + if (!any_m) { + jsondec_err(d, "Any object didn't contain a '@type' field"); + } -UPB_FORCEINLINE -static void* fastdecode_fieldmem(upb_Message* msg, uint64_t data) { - size_t ofs = data >> 48; - return (char*)msg + ofs; -} + any_msg = upb_Message_New(any_m, d->arena); -UPB_FORCEINLINE -static void* fastdecode_getfield(upb_Decoder* d, const char* ptr, - upb_Message* msg, uint64_t* data, - uint64_t* hasbits, fastdecode_arr* farr, - int valbytes, upb_card card) { - switch (card) { - case CARD_s: { - uint8_t hasbit_index = *data >> 24; - // Set hasbit and return pointer to scalar field. - *hasbits |= 1ull << hasbit_index; - return fastdecode_fieldmem(msg, *data); - } - case CARD_o: { - uint16_t case_ofs = *data >> 32; - uint32_t* oneof_case = UPB_PTR_AT(msg, case_ofs, uint32_t); - uint8_t field_number = *data >> 24; - *oneof_case = field_number; - return fastdecode_fieldmem(msg, *data); - } - case CARD_r: { - // Get pointer to upb_Array and allocate/expand if necessary. - uint8_t elem_size_lg2 = __builtin_ctz(valbytes); - upb_Array** arr_p = fastdecode_fieldmem(msg, *data); - char* begin; - *(uint32_t*)msg |= *hasbits; - *hasbits = 0; - if (UPB_LIKELY(!*arr_p)) { - farr->arr = _upb_Array_New(&d->arena, 8, elem_size_lg2); - *arr_p = farr->arr; - } else { - farr->arr = *arr_p; - } - begin = _upb_array_ptr(farr->arr); - farr->end = begin + (farr->arr->size * valbytes); - *data = fastdecode_loadtag(ptr); - return begin + (farr->arr->len * valbytes); + if (pre_type_data) { + size_t len = pre_type_end - pre_type_data + 1; + char* tmp = upb_Arena_Malloc(d->arena, len); + const char* saved_ptr = d->ptr; + const char* saved_end = d->end; + memcpy(tmp, pre_type_data, len - 1); + tmp[len - 1] = '}'; + d->ptr = tmp; + d->end = tmp + len; + d->is_first = true; + while (jsondec_objnext(d)) { + jsondec_anyfield(d, any_msg, any_m); } - default: - UPB_UNREACHABLE(); + d->ptr = saved_ptr; + d->end = saved_end; } -} - -UPB_FORCEINLINE -static bool fastdecode_flippacked(uint64_t* data, int tagbytes) { - *data ^= (0x2 ^ 0x0); // Patch data to match packed wiretype. - return fastdecode_checktag(*data, tagbytes); -} -#define FASTDECODE_CHECKPACKED(tagbytes, card, func) \ - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ - if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) { \ - UPB_MUSTTAIL return func(UPB_PARSE_ARGS); \ - } \ - RETURN_GENERIC("packed check tag mismatch\n"); \ + while (jsondec_objnext(d)) { + jsondec_anyfield(d, any_msg, any_m); } -/* varint fields **************************************************************/ + jsondec_objend(d); -UPB_FORCEINLINE -static uint64_t fastdecode_munge(uint64_t val, int valbytes, bool zigzag) { - if (valbytes == 1) { - return val != 0; - } else if (zigzag) { - if (valbytes == 4) { - uint32_t n = val; - return (n >> 1) ^ -(int32_t)(n & 1); - } else if (valbytes == 8) { - return (val >> 1) ^ -(int64_t)(val & 1); - } - UPB_UNREACHABLE(); - } - return val; + upb_EncodeStatus status = + upb_Encode(any_msg, upb_MessageDef_MiniTable(any_m), 0, d->arena, + (char**)&encoded.str_val.data, &encoded.str_val.size); + // TODO(b/235839510): We should fail gracefully here on a bad return status. + UPB_ASSERT(status == kUpb_EncodeStatus_Ok); + upb_Message_Set(msg, value_f, encoded, d->arena); } -UPB_FORCEINLINE -static const char* fastdecode_varint64(const char* ptr, uint64_t* val) { - ptr++; - *val = (uint8_t)ptr[-1]; - if (UPB_UNLIKELY(*val & 0x80)) { - int i; - for (i = 0; i < 8; i++) { - ptr++; - uint64_t byte = (uint8_t)ptr[-1]; - *val += (byte - 1) << (7 + 7 * i); - if (UPB_LIKELY((byte & 0x80) == 0)) goto done; - } - ptr++; - uint64_t byte = (uint8_t)ptr[-1]; - if (byte > 1) { - return NULL; - } - *val += (byte - 1) << 63; +static void jsondec_wrapper(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_MessageValue val = jsondec_value(d, value_f); + upb_Message_Set(msg, value_f, val, d->arena); +} + +static void jsondec_wellknown(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + switch (upb_MessageDef_WellKnownType(m)) { + case kUpb_WellKnown_Any: + jsondec_any(d, msg, m); + break; + case kUpb_WellKnown_FieldMask: + jsondec_fieldmask(d, msg, m); + break; + case kUpb_WellKnown_Duration: + jsondec_duration(d, msg, m); + break; + case kUpb_WellKnown_Timestamp: + jsondec_timestamp(d, msg, m); + break; + case kUpb_WellKnown_Value: + jsondec_wellknownvalue(d, msg, m); + break; + case kUpb_WellKnown_ListValue: + jsondec_listvalue(d, msg, m); + break; + case kUpb_WellKnown_Struct: + jsondec_struct(d, msg, m); + break; + case kUpb_WellKnown_DoubleValue: + case kUpb_WellKnown_FloatValue: + case kUpb_WellKnown_Int64Value: + case kUpb_WellKnown_UInt64Value: + case kUpb_WellKnown_Int32Value: + case kUpb_WellKnown_UInt32Value: + case kUpb_WellKnown_StringValue: + case kUpb_WellKnown_BytesValue: + case kUpb_WellKnown_BoolValue: + jsondec_wrapper(d, msg, m); + break; + default: + UPB_UNREACHABLE(); } -done: - UPB_ASSUME(ptr != NULL); - return ptr; } -#define FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, zigzag, packed) \ - uint64_t val; \ - void* dst; \ - fastdecode_arr farr; \ - \ - FASTDECODE_CHECKPACKED(tagbytes, card, packed); \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ - card); \ - if (card == CARD_r) { \ - if (UPB_UNLIKELY(!dst)) { \ - RETURN_GENERIC("need array resize\n"); \ - } \ - } \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ - } \ - \ - ptr += tagbytes; \ - ptr = fastdecode_varint64(ptr, &val); \ - if (ptr == NULL) return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - val = fastdecode_munge(val, valbytes, zigzag); \ - memcpy(dst, &val, valbytes); \ - \ - if (card == CARD_r) { \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, valbytes); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, + const upb_MessageDef* m, const upb_DefPool* symtab, + int options, upb_Arena* arena, upb_Status* status) { + jsondec d; -typedef struct { - uint8_t valbytes; - bool zigzag; - void* dst; - fastdecode_arr farr; -} fastdecode_varintdata; + if (size == 0) return true; -UPB_FORCEINLINE -static const char* fastdecode_topackedvarint(upb_Decoder* d, const char* ptr, - void* ctx) { - fastdecode_varintdata* data = ctx; - void* dst = data->dst; - uint64_t val; + d.ptr = buf; + d.end = buf + size; + d.arena = arena; + d.symtab = symtab; + d.status = status; + d.options = options; + d.depth = 64; + d.line = 1; + d.line_begin = d.ptr; + d.debug_field = NULL; + d.is_first = false; - while (!decode_isdone(d, &ptr)) { - dst = fastdecode_resizearr(d, dst, &data->farr, data->valbytes); - ptr = fastdecode_varint64(ptr, &val); - if (ptr == NULL) return NULL; - val = fastdecode_munge(val, data->valbytes, data->zigzag); - memcpy(dst, &val, data->valbytes); - dst = (char*)dst + data->valbytes; - } + if (UPB_SETJMP(d.err)) return false; - fastdecode_commitarr(dst, &data->farr, data->valbytes); - return ptr; + jsondec_tomsg(&d, msg, m); + return true; } -#define FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, zigzag, unpacked) \ - fastdecode_varintdata ctx = {valbytes, zigzag}; \ - \ - FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked); \ - \ - ctx.dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &ctx.farr, \ - valbytes, CARD_r); \ - if (UPB_UNLIKELY(!ctx.dst)) { \ - RETURN_GENERIC("need array resize\n"); \ - } \ - \ - ptr += tagbytes; \ - ptr = fastdecode_delimited(d, ptr, &fastdecode_topackedvarint, &ctx); \ - \ - if (UPB_UNLIKELY(ptr == NULL)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(d, ptr, msg, table, hasbits, 0); - -#define FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, zigzag, unpacked, packed) \ - if (card == CARD_p) { \ - FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, zigzag, unpacked); \ - } else { \ - FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, zigzag, packed); \ - } -#define z_ZZ true -#define b_ZZ false -#define v_ZZ false +#include +#include +#include +#include +#include +#include +#include -/* Generate all combinations: - * {s,o,r,p} x {b1,v4,z4,v8,z8} x {1bt,2bt} */ -#define F(card, type, valbytes, tagbytes) \ - UPB_NOINLINE \ - const char* upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ - CARD_##card, type##_ZZ, \ - upb_pr##type##valbytes##_##tagbytes##bt, \ - upb_pp##type##valbytes##_##tagbytes##bt); \ - } +// Must be last. -#define TYPES(card, tagbytes) \ - F(card, b, 1, tagbytes) \ - F(card, v, 4, tagbytes) \ - F(card, v, 8, tagbytes) \ - F(card, z, 4, tagbytes) \ - F(card, z, 8, tagbytes) +typedef struct { + char *buf, *ptr, *end; + size_t overflow; + int indent_depth; + int options; + const upb_DefPool* ext_pool; + jmp_buf err; + upb_Status* status; + upb_Arena* arena; +} jsonenc; -#define TAGBYTES(card) \ - TYPES(card, 1) \ - TYPES(card, 2) +static void jsonenc_msg(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); +static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f); +static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); +static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m, bool first); +static void jsonenc_value(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) -TAGBYTES(p) +UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) { + upb_Status_SetErrorMessage(e->status, msg); + longjmp(e->err, 1); +} -#undef z_ZZ -#undef b_ZZ -#undef v_ZZ -#undef o_ONEOF -#undef s_ONEOF -#undef r_ONEOF -#undef F -#undef TYPES -#undef TAGBYTES -#undef FASTDECODE_UNPACKEDVARINT -#undef FASTDECODE_PACKEDVARINT -#undef FASTDECODE_VARINT +UPB_PRINTF(2, 3) +UPB_NORETURN static void jsonenc_errf(jsonenc* e, const char* fmt, ...) { + va_list argp; + va_start(argp, fmt); + upb_Status_VSetErrorFormat(e->status, fmt, argp); + va_end(argp); + longjmp(e->err, 1); +} -/* fixed fields ***************************************************************/ +static upb_Arena* jsonenc_arena(jsonenc* e) { + /* Create lazily, since it's only needed for Any */ + if (!e->arena) { + e->arena = upb_Arena_New(); + } + return e->arena; +} -#define FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, packed) \ - void* dst; \ - fastdecode_arr farr; \ - \ - FASTDECODE_CHECKPACKED(tagbytes, card, packed) \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ - card); \ - if (card == CARD_r) { \ - if (UPB_UNLIKELY(!dst)) { \ - RETURN_GENERIC("couldn't allocate array in arena\n"); \ - } \ - } \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ - } \ - \ - ptr += tagbytes; \ - memcpy(dst, ptr, valbytes); \ - ptr += valbytes; \ - \ - if (card == CARD_r) { \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, valbytes); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +static void jsonenc_putbytes(jsonenc* e, const void* data, size_t len) { + size_t have = e->end - e->ptr; + if (UPB_LIKELY(have >= len)) { + memcpy(e->ptr, data, len); + e->ptr += len; + } else { + if (have) { + memcpy(e->ptr, data, have); + e->ptr += have; + } + e->overflow += (len - have); + } +} -#define FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, unpacked) \ - FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked) \ - \ - ptr += tagbytes; \ - int size = (uint8_t)ptr[0]; \ - ptr++; \ - if (size & 0x80) { \ - ptr = fastdecode_longsize(ptr, &size); \ - } \ - \ - if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr) || \ - (size % valbytes) != 0)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - \ - upb_Array** arr_p = fastdecode_fieldmem(msg, data); \ - upb_Array* arr = *arr_p; \ - uint8_t elem_size_lg2 = __builtin_ctz(valbytes); \ - int elems = size / valbytes; \ - \ - if (UPB_LIKELY(!arr)) { \ - *arr_p = arr = _upb_Array_New(&d->arena, elems, elem_size_lg2); \ - if (!arr) { \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - } else { \ - _upb_Array_Resize(arr, elems, &d->arena); \ - } \ - \ - char* dst = _upb_array_ptr(arr); \ - memcpy(dst, ptr, size); \ - arr->len = elems; \ - \ - ptr += size; \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +static void jsonenc_putstr(jsonenc* e, const char* str) { + jsonenc_putbytes(e, str, strlen(str)); +} -#define FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, unpacked, packed) \ - if (card == CARD_p) { \ - FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, unpacked); \ - } else { \ - FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, packed); \ +UPB_PRINTF(2, 3) +static void jsonenc_printf(jsonenc* e, const char* fmt, ...) { + size_t n; + size_t have = e->end - e->ptr; + va_list args; + + va_start(args, fmt); + n = _upb_vsnprintf(e->ptr, have, fmt, args); + va_end(args); + + if (UPB_LIKELY(have > n)) { + e->ptr += n; + } else { + e->ptr = UPB_PTRADD(e->ptr, have); + e->overflow += (n - have); } +} -/* Generate all combinations: - * {s,o,r,p} x {f4,f8} x {1bt,2bt} */ +static void jsonenc_nanos(jsonenc* e, int32_t nanos) { + int digits = 9; -#define F(card, valbytes, tagbytes) \ - UPB_NOINLINE \ - const char* upb_p##card##f##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ - CARD_##card, upb_ppf##valbytes##_##tagbytes##bt, \ - upb_prf##valbytes##_##tagbytes##bt); \ + if (nanos == 0) return; + if (nanos < 0 || nanos >= 1000000000) { + jsonenc_err(e, "error formatting timestamp as JSON: invalid nanos"); } -#define TYPES(card, tagbytes) \ - F(card, 4, tagbytes) \ - F(card, 8, tagbytes) + while (nanos % 1000 == 0) { + nanos /= 1000; + digits -= 3; + } -#define TAGBYTES(card) \ - TYPES(card, 1) \ - TYPES(card, 2) + jsonenc_printf(e, ".%.*" PRId32, digits, nanos); +} -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) -TAGBYTES(p) +static void jsonenc_timestamp(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); + int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; + int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; + int L, N, I, J, K, hour, min, sec; -#undef F -#undef TYPES -#undef TAGBYTES -#undef FASTDECODE_UNPACKEDFIXED -#undef FASTDECODE_PACKEDFIXED + if (seconds < -62135596800) { + jsonenc_err(e, + "error formatting timestamp as JSON: minimum acceptable value " + "is 0001-01-01T00:00:00Z"); + } else if (seconds > 253402300799) { + jsonenc_err(e, + "error formatting timestamp as JSON: maximum acceptable value " + "is 9999-12-31T23:59:59Z"); + } -/* string fields **************************************************************/ + /* Julian Day -> Y/M/D, Algorithm from: + * Fliegel, H. F., and Van Flandern, T. C., "A Machine Algorithm for + * Processing Calendar Dates," Communications of the Association of + * Computing Machines, vol. 11 (1968), p. 657. */ + seconds += 62135596800; // Ensure seconds is positive. + L = (int)(seconds / 86400) - 719162 + 68569 + 2440588; + N = 4 * L / 146097; + L = L - (146097 * N + 3) / 4; + I = 4000 * (L + 1) / 1461001; + L = L - 1461 * I / 4 + 31; + J = 80 * L / 2447; + K = L - 2447 * J / 80; + L = J / 11; + J = J + 2 - 12 * L; + I = 100 * (N - 49) + I + L; -typedef const char* fastdecode_copystr_func(struct upb_Decoder* d, - const char* ptr, upb_Message* msg, - const upb_MiniTable* table, - uint64_t hasbits, - upb_StringView* dst); + sec = seconds % 60; + min = (seconds / 60) % 60; + hour = (seconds / 3600) % 24; -UPB_NOINLINE -static const char* fastdecode_verifyutf8(upb_Decoder* d, const char* ptr, - upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t data) { - upb_StringView* dst = (upb_StringView*)data; - if (!decode_verifyutf8_inl(dst->data, dst->size)) { - return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8); - } - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec); + jsonenc_nanos(e, nanos); + jsonenc_putstr(e, "Z\""); } -#define FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, validate_utf8) \ - int size = (uint8_t)ptr[0]; /* Could plumb through hasbits. */ \ - ptr++; \ - if (size & 0x80) { \ - ptr = fastdecode_longsize(ptr, &size); \ - } \ - \ - if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr))) { \ - dst->size = 0; \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - \ - if (d->options & kUpb_DecodeOption_AliasString) { \ - dst->data = ptr; \ - dst->size = size; \ - } else { \ - char* data = upb_Arena_Malloc(&d->arena, size); \ - if (!data) { \ - return fastdecode_err(d, kUpb_DecodeStatus_OutOfMemory); \ - } \ - memcpy(data, ptr, size); \ - dst->data = data; \ - dst->size = size; \ - } \ - \ - ptr += size; \ - if (validate_utf8) { \ - data = (uint64_t)dst; \ - UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ - } else { \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ +static void jsonenc_duration(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); + int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; + int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; + bool negative = false; + + if (seconds > 315576000000 || seconds < -315576000000 || + (seconds != 0 && nanos != 0 && (seconds < 0) != (nanos < 0))) { + jsonenc_err(e, "bad duration"); } -UPB_NOINLINE -static const char* fastdecode_longstring_utf8(struct upb_Decoder* d, - const char* ptr, upb_Message* msg, - intptr_t table, uint64_t hasbits, - uint64_t data) { - upb_StringView* dst = (upb_StringView*)data; - FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, true); + if (seconds < 0) { + negative = true; + seconds = -seconds; + } + if (nanos < 0) { + negative = true; + nanos = -nanos; + } + + jsonenc_putstr(e, "\""); + if (negative) { + jsonenc_putstr(e, "-"); + } + jsonenc_printf(e, "%" PRId64, seconds); + jsonenc_nanos(e, nanos); + jsonenc_putstr(e, "s\""); } -UPB_NOINLINE -static const char* fastdecode_longstring_noutf8( - struct upb_Decoder* d, const char* ptr, upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t data) { - upb_StringView* dst = (upb_StringView*)data; - FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, false); +static void jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) { + const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f); + + if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) { + jsonenc_putstr(e, "null"); + } else { + const upb_EnumValueDef* ev = + (e->options & upb_JsonEncode_FormatEnumsAsIntegers) + ? NULL + : upb_EnumDef_FindValueByNumber(e_def, val); + + if (ev) { + jsonenc_printf(e, "\"%s\"", upb_EnumValueDef_Name(ev)); + } else { + jsonenc_printf(e, "%" PRId32, val); + } + } +} + +static void jsonenc_bytes(jsonenc* e, upb_StringView str) { + /* This is the regular base64, not the "web-safe" version. */ + static const char base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + const unsigned char* ptr = (unsigned char*)str.data; + const unsigned char* end = UPB_PTRADD(ptr, str.size); + char buf[4]; + + jsonenc_putstr(e, "\""); + + while (end - ptr >= 3) { + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; + buf[2] = base64[((ptr[1] & 0xf) << 2) | (ptr[2] >> 6)]; + buf[3] = base64[ptr[2] & 0x3f]; + jsonenc_putbytes(e, buf, 4); + ptr += 3; + } + + switch (end - ptr) { + case 2: + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; + buf[2] = base64[(ptr[1] & 0xf) << 2]; + buf[3] = '='; + jsonenc_putbytes(e, buf, 4); + break; + case 1: + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4)]; + buf[2] = '='; + buf[3] = '='; + jsonenc_putbytes(e, buf, 4); + break; + } + + jsonenc_putstr(e, "\""); +} + +static void jsonenc_stringbody(jsonenc* e, upb_StringView str) { + const char* ptr = str.data; + const char* end = UPB_PTRADD(ptr, str.size); + + while (ptr < end) { + switch (*ptr) { + case '\n': + jsonenc_putstr(e, "\\n"); + break; + case '\r': + jsonenc_putstr(e, "\\r"); + break; + case '\t': + jsonenc_putstr(e, "\\t"); + break; + case '\"': + jsonenc_putstr(e, "\\\""); + break; + case '\f': + jsonenc_putstr(e, "\\f"); + break; + case '\b': + jsonenc_putstr(e, "\\b"); + break; + case '\\': + jsonenc_putstr(e, "\\\\"); + break; + default: + if ((uint8_t)*ptr < 0x20) { + jsonenc_printf(e, "\\u%04x", (int)(uint8_t)*ptr); + } else { + /* This could be a non-ASCII byte. We rely on the string being valid + * UTF-8. */ + jsonenc_putbytes(e, ptr, 1); + } + break; + } + ptr++; + } +} + +static void jsonenc_string(jsonenc* e, upb_StringView str) { + jsonenc_putstr(e, "\""); + jsonenc_stringbody(e, str); + jsonenc_putstr(e, "\""); +} + +static bool upb_JsonEncode_HandleSpecialDoubles(jsonenc* e, double val) { + if (val == INFINITY) { + jsonenc_putstr(e, "\"Infinity\""); + } else if (val == -INFINITY) { + jsonenc_putstr(e, "\"-Infinity\""); + } else if (val != val) { + jsonenc_putstr(e, "\"NaN\""); + } else { + return false; + } + return true; +} + +static void upb_JsonEncode_Double(jsonenc* e, double val) { + if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; + char buf[32]; + _upb_EncodeRoundTripDouble(val, buf, sizeof(buf)); + jsonenc_putstr(e, buf); +} + +static void upb_JsonEncode_Float(jsonenc* e, float val) { + if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; + char buf[32]; + _upb_EncodeRoundTripFloat(val, buf, sizeof(buf)); + jsonenc_putstr(e, buf); +} + +static void jsonenc_wrapper(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_MessageValue val = upb_Message_Get(msg, val_f); + jsonenc_scalar(e, val, val_f); +} + +static const upb_MessageDef* jsonenc_getanymsg(jsonenc* e, + upb_StringView type_url) { + /* Find last '/', if any. */ + const char* end = type_url.data + type_url.size; + const char* ptr = end; + const upb_MessageDef* ret; + + if (!e->ext_pool) { + jsonenc_err(e, "Tried to encode Any, but no symtab was provided"); + } + + if (type_url.size == 0) goto badurl; + + while (true) { + if (--ptr == type_url.data) { + /* Type URL must contain at least one '/', with host before. */ + goto badurl; + } + if (*ptr == '/') { + ptr++; + break; + } + } + + ret = upb_DefPool_FindMessageByNameWithSize(e->ext_pool, ptr, end - ptr); + + if (!ret) { + jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr); + } + + return ret; + +badurl: + jsonenc_errf(e, "Bad type URL: " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(type_url)); +} + +static void jsonenc_any(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); + upb_StringView type_url = upb_Message_Get(msg, type_url_f).str_val; + upb_StringView value = upb_Message_Get(msg, value_f).str_val; + const upb_MessageDef* any_m = jsonenc_getanymsg(e, type_url); + const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m); + upb_Arena* arena = jsonenc_arena(e); + upb_Message* any = upb_Message_New(any_m, arena); + + if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + jsonenc_err(e, "Error decoding message in Any"); + } + + jsonenc_putstr(e, "{\"@type\":"); + jsonenc_string(e, type_url); + + if (upb_MessageDef_WellKnownType(any_m) == kUpb_WellKnown_Unspecified) { + /* Regular messages: {"@type": "...","foo": 1, "bar": 2} */ + jsonenc_msgfields(e, any, any_m, false); + } else { + /* Well-known type: {"@type": "...","value": } */ + jsonenc_putstr(e, ",\"value\":"); + jsonenc_msgfield(e, any, any_m); + } + + jsonenc_putstr(e, "}"); +} + +static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) { + if (*first) { + *first = false; + } else { + jsonenc_putstr(e, str); + } +} + +static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) { + const char* ptr = path.data; + const char* end = ptr + path.size; + + while (ptr < end) { + char ch = *ptr; + + if (ch >= 'A' && ch <= 'Z') { + jsonenc_err(e, "Field mask element may not have upper-case letter."); + } else if (ch == '_') { + if (ptr == end - 1 || *(ptr + 1) < 'a' || *(ptr + 1) > 'z') { + jsonenc_err(e, "Underscore must be followed by a lowercase letter."); + } + ch = *++ptr - 32; + } + + jsonenc_putbytes(e, &ch, 1); + ptr++; + } +} + +static void jsonenc_fieldmask(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_Array* paths = upb_Message_Get(msg, paths_f).array_val; + bool first = true; + size_t i, n = 0; + + if (paths) n = upb_Array_Size(paths); + + jsonenc_putstr(e, "\""); + + for (i = 0; i < n; i++) { + jsonenc_putsep(e, ",", &first); + jsonenc_fieldpath(e, upb_Array_Get(paths, i).str_val); + } + + jsonenc_putstr(e, "\""); +} + +static void jsonenc_struct(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_Map* fields = upb_Message_Get(msg, fields_f).map_val; + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + size_t iter = kUpb_Map_Begin; + bool first = true; + + jsonenc_putstr(e, "{"); + + if (fields) { + while (upb_MapIterator_Next(fields, &iter)) { + upb_MessageValue key = upb_MapIterator_Key(fields, iter); + upb_MessageValue val = upb_MapIterator_Value(fields, iter); + + jsonenc_putsep(e, ",", &first); + jsonenc_string(e, key.str_val); + jsonenc_putstr(e, ":"); + jsonenc_value(e, val.msg_val, upb_FieldDef_MessageSubDef(value_f)); + } + } + + jsonenc_putstr(e, "}"); +} + +static void jsonenc_listvalue(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* values_m = upb_FieldDef_MessageSubDef(values_f); + const upb_Array* values = upb_Message_Get(msg, values_f).array_val; + size_t i; + bool first = true; + + jsonenc_putstr(e, "["); + + if (values) { + const size_t size = upb_Array_Size(values); + for (i = 0; i < size; i++) { + upb_MessageValue elem = upb_Array_Get(values, i); + + jsonenc_putsep(e, ",", &first); + jsonenc_value(e, elem.msg_val, values_m); + } + } + + jsonenc_putstr(e, "]"); +} + +static void jsonenc_value(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + /* TODO(haberman): do we want a reflection method to get oneof case? */ + size_t iter = kUpb_Message_Begin; + const upb_FieldDef* f; + upb_MessageValue val; + + if (!upb_Message_Next(msg, m, NULL, &f, &val, &iter)) { + jsonenc_err(e, "No value set in Value proto"); + } + + switch (upb_FieldDef_Number(f)) { + case 1: + jsonenc_putstr(e, "null"); + break; + case 2: + upb_JsonEncode_Double(e, val.double_val); + break; + case 3: + jsonenc_string(e, val.str_val); + break; + case 4: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case 5: + jsonenc_struct(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + case 6: + jsonenc_listvalue(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + } +} + +static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + switch (upb_MessageDef_WellKnownType(m)) { + case kUpb_WellKnown_Unspecified: + jsonenc_msg(e, msg, m); + break; + case kUpb_WellKnown_Any: + jsonenc_any(e, msg, m); + break; + case kUpb_WellKnown_FieldMask: + jsonenc_fieldmask(e, msg, m); + break; + case kUpb_WellKnown_Duration: + jsonenc_duration(e, msg, m); + break; + case kUpb_WellKnown_Timestamp: + jsonenc_timestamp(e, msg, m); + break; + case kUpb_WellKnown_DoubleValue: + case kUpb_WellKnown_FloatValue: + case kUpb_WellKnown_Int64Value: + case kUpb_WellKnown_UInt64Value: + case kUpb_WellKnown_Int32Value: + case kUpb_WellKnown_UInt32Value: + case kUpb_WellKnown_StringValue: + case kUpb_WellKnown_BytesValue: + case kUpb_WellKnown_BoolValue: + jsonenc_wrapper(e, msg, m); + break; + case kUpb_WellKnown_Value: + jsonenc_value(e, msg, m); + break; + case kUpb_WellKnown_ListValue: + jsonenc_listvalue(e, msg, m); + break; + case kUpb_WellKnown_Struct: + jsonenc_struct(e, msg, m); + break; + } +} + +static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case kUpb_CType_Float: + upb_JsonEncode_Float(e, val.float_val); + break; + case kUpb_CType_Double: + upb_JsonEncode_Double(e, val.double_val); + break; + case kUpb_CType_Int32: + jsonenc_printf(e, "%" PRId32, val.int32_val); + break; + case kUpb_CType_UInt32: + jsonenc_printf(e, "%" PRIu32, val.uint32_val); + break; + case kUpb_CType_Int64: + jsonenc_printf(e, "\"%" PRId64 "\"", val.int64_val); + break; + case kUpb_CType_UInt64: + jsonenc_printf(e, "\"%" PRIu64 "\"", val.uint64_val); + break; + case kUpb_CType_String: + jsonenc_string(e, val.str_val); + break; + case kUpb_CType_Bytes: + jsonenc_bytes(e, val.str_val); + break; + case kUpb_CType_Enum: + jsonenc_enum(val.int32_val, f, e); + break; + case kUpb_CType_Message: + jsonenc_msgfield(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + } +} + +static void jsonenc_mapkey(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f) { + jsonenc_putstr(e, "\""); + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case kUpb_CType_Int32: + jsonenc_printf(e, "%" PRId32, val.int32_val); + break; + case kUpb_CType_UInt32: + jsonenc_printf(e, "%" PRIu32, val.uint32_val); + break; + case kUpb_CType_Int64: + jsonenc_printf(e, "%" PRId64, val.int64_val); + break; + case kUpb_CType_UInt64: + jsonenc_printf(e, "%" PRIu64, val.uint64_val); + break; + case kUpb_CType_String: + jsonenc_stringbody(e, val.str_val); + break; + default: + UPB_UNREACHABLE(); + } + + jsonenc_putstr(e, "\":"); +} + +static void jsonenc_array(jsonenc* e, const upb_Array* arr, + const upb_FieldDef* f) { + size_t i; + size_t size = arr ? upb_Array_Size(arr) : 0; + bool first = true; + + jsonenc_putstr(e, "["); + + for (i = 0; i < size; i++) { + jsonenc_putsep(e, ",", &first); + jsonenc_scalar(e, upb_Array_Get(arr, i), f); + } + + jsonenc_putstr(e, "]"); +} + +static void jsonenc_map(jsonenc* e, const upb_Map* map, const upb_FieldDef* f) { + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); + size_t iter = kUpb_Map_Begin; + bool first = true; + + jsonenc_putstr(e, "{"); + + if (map) { + while (upb_MapIterator_Next(map, &iter)) { + jsonenc_putsep(e, ",", &first); + jsonenc_mapkey(e, upb_MapIterator_Key(map, iter), key_f); + jsonenc_scalar(e, upb_MapIterator_Value(map, iter), val_f); + } + } + + jsonenc_putstr(e, "}"); +} + +static void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f, + upb_MessageValue val, bool* first) { + const char* name; + + jsonenc_putsep(e, ",", first); + + if (upb_FieldDef_IsExtension(f)) { + // TODO: For MessageSet, I would have expected this to print the message + // name here, but Python doesn't appear to do this. We should do more + // research here about what various implementations do. + jsonenc_printf(e, "\"[%s]\":", upb_FieldDef_FullName(f)); + } else { + if (e->options & upb_JsonEncode_UseProtoNames) { + name = upb_FieldDef_Name(f); + } else { + name = upb_FieldDef_JsonName(f); + } + jsonenc_printf(e, "\"%s\":", name); + } + + if (upb_FieldDef_IsMap(f)) { + jsonenc_map(e, val.map_val, f); + } else if (upb_FieldDef_IsRepeated(f)) { + jsonenc_array(e, val.array_val, f); + } else { + jsonenc_scalar(e, val, f); + } +} + +static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m, bool first) { + upb_MessageValue val; + const upb_FieldDef* f; + + if (e->options & upb_JsonEncode_EmitDefaults) { + /* Iterate over all fields. */ + int i = 0; + int n = upb_MessageDef_FieldCount(m); + for (i = 0; i < n; i++) { + f = upb_MessageDef_Field(m, i); + if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) { + jsonenc_fieldval(e, f, upb_Message_Get(msg, f), &first); + } + } + } else { + /* Iterate over non-empty fields. */ + size_t iter = kUpb_Message_Begin; + while (upb_Message_Next(msg, m, e->ext_pool, &f, &val, &iter)) { + jsonenc_fieldval(e, f, val, &first); + } + } +} + +static void jsonenc_msg(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + jsonenc_putstr(e, "{"); + jsonenc_msgfields(e, msg, m, true); + jsonenc_putstr(e, "}"); +} + +static size_t jsonenc_nullz(jsonenc* e, size_t size) { + size_t ret = e->ptr - e->buf + e->overflow; + + if (size > 0) { + if (e->ptr == e->end) e->ptr--; + *e->ptr = '\0'; + } + + return ret; +} + +size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, int options, char* buf, + size_t size, upb_Status* status) { + jsonenc e; + + e.buf = buf; + e.ptr = buf; + e.end = UPB_PTRADD(buf, size); + e.overflow = 0; + e.options = options; + e.ext_pool = ext_pool; + e.status = status; + e.arena = NULL; + + if (setjmp(e.err)) return -1; + + jsonenc_msgfield(&e, msg, m); + if (e.arena) upb_Arena_Free(e.arena); + return jsonenc_nullz(&e, size); +} + + +#include +#include + + +// Must be last. + +typedef enum { + kUpb_EncodedType_Double = 0, + kUpb_EncodedType_Float = 1, + kUpb_EncodedType_Fixed32 = 2, + kUpb_EncodedType_Fixed64 = 3, + kUpb_EncodedType_SFixed32 = 4, + kUpb_EncodedType_SFixed64 = 5, + kUpb_EncodedType_Int32 = 6, + kUpb_EncodedType_UInt32 = 7, + kUpb_EncodedType_SInt32 = 8, + kUpb_EncodedType_Int64 = 9, + kUpb_EncodedType_UInt64 = 10, + kUpb_EncodedType_SInt64 = 11, + kUpb_EncodedType_Enum = 12, + kUpb_EncodedType_Bool = 13, + kUpb_EncodedType_Bytes = 14, + kUpb_EncodedType_String = 15, + kUpb_EncodedType_Group = 16, + kUpb_EncodedType_Message = 17, + + kUpb_EncodedType_RepeatedBase = 20, +} upb_EncodedType; + +typedef enum { + kUpb_EncodedFieldModifier_FlipPacked = 1 << 0, + kUpb_EncodedFieldModifier_IsClosedEnum = 1 << 1, + // upb only. + kUpb_EncodedFieldModifier_IsProto3Singular = 1 << 2, + kUpb_EncodedFieldModifier_IsRequired = 1 << 3, +} upb_EncodedFieldModifier; + +enum { + kUpb_EncodedValue_MinField = ' ', + kUpb_EncodedValue_MaxField = 'K', + kUpb_EncodedValue_MinModifier = 'L', + kUpb_EncodedValue_MaxModifier = '[', + kUpb_EncodedValue_End = '^', + kUpb_EncodedValue_MinSkip = '_', + kUpb_EncodedValue_MaxSkip = '~', + kUpb_EncodedValue_OneofSeparator = '~', + kUpb_EncodedValue_FieldSeparator = '|', + kUpb_EncodedValue_MinOneofField = ' ', + kUpb_EncodedValue_MaxOneofField = 'b', + kUpb_EncodedValue_MaxEnumMask = 'A', +}; + +char upb_ToBase92(int8_t ch) { + static const char kUpb_ToBase92[] = { + ' ', '!', '#', '$', '%', '&', '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', + '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', + 'Z', '[', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '{', '|', '}', '~', + }; + + UPB_ASSERT(0 <= ch && ch < 92); + return kUpb_ToBase92[ch]; +} + +char upb_FromBase92(uint8_t ch) { + static const int8_t kUpb_FromBase92[] = { + 0, 1, -1, 2, 3, 4, 5, -1, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + }; + + if (' ' > ch || ch > '~') return -1; + return kUpb_FromBase92[ch - ' ']; +} + +bool upb_IsTypePackable(upb_FieldType type) { + // clang-format off + static const unsigned kUnpackableTypes = + (1 << kUpb_FieldType_String) | + (1 << kUpb_FieldType_Bytes) | + (1 << kUpb_FieldType_Message) | + (1 << kUpb_FieldType_Group); + // clang-format on + return (1 << type) & ~kUnpackableTypes; +} + +/** upb_MtDataEncoder *********************************************************/ + +typedef struct { + uint64_t present_values_mask; + uint32_t last_written_value; +} upb_MtDataEncoderInternal_EnumState; + +typedef struct { + uint64_t msg_modifiers; + uint32_t last_field_num; + enum { + kUpb_OneofState_NotStarted, + kUpb_OneofState_StartedOneof, + kUpb_OneofState_EmittedOneofField, + } oneof_state; +} upb_MtDataEncoderInternal_MsgState; + +typedef struct { + char* buf_start; // Only for checking kUpb_MtDataEncoder_MinSize. + union { + upb_MtDataEncoderInternal_EnumState enum_state; + upb_MtDataEncoderInternal_MsgState msg_state; + } state; +} upb_MtDataEncoderInternal; + +static upb_MtDataEncoderInternal* upb_MtDataEncoder_GetInternal( + upb_MtDataEncoder* e, char* buf_start) { + UPB_ASSERT(sizeof(upb_MtDataEncoderInternal) <= sizeof(e->internal)); + upb_MtDataEncoderInternal* ret = (upb_MtDataEncoderInternal*)e->internal; + ret->buf_start = buf_start; + return ret; } -UPB_FORCEINLINE -static void fastdecode_docopy(upb_Decoder* d, const char* ptr, uint32_t size, - int copy, char* data, upb_StringView* dst) { - d->arena.head.ptr += copy; - dst->data = data; - UPB_UNPOISON_MEMORY_REGION(data, copy); - memcpy(data, ptr, copy); - UPB_POISON_MEMORY_REGION(data + size, copy - size); +static char* upb_MtDataEncoder_Put(upb_MtDataEncoder* e, char* ptr, char ch) { + upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; + UPB_ASSERT(ptr - in->buf_start < kUpb_MtDataEncoder_MinSize); + if (ptr == e->end) return NULL; + *ptr++ = upb_ToBase92(ch); + return ptr; } -#define FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ - card, validate_utf8) \ - upb_StringView* dst; \ - fastdecode_arr farr; \ - int64_t size; \ - size_t arena_has; \ - size_t common_has; \ - char* buf; \ - \ - UPB_ASSERT((d->options & kUpb_DecodeOption_AliasString) == 0); \ - UPB_ASSERT(fastdecode_checktag(data, tagbytes)); \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ - sizeof(upb_StringView), card); \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView)); \ - } \ - \ - size = (uint8_t)ptr[tagbytes]; \ - ptr += tagbytes + 1; \ - dst->size = size; \ - \ - buf = d->arena.head.ptr; \ - arena_has = _upb_ArenaHas(&d->arena); \ - common_has = UPB_MIN(arena_has, (d->end - ptr) + 16); \ - \ - if (UPB_LIKELY(size <= 15 - tagbytes)) { \ - if (arena_has < 16) goto longstr; \ - d->arena.head.ptr += 16; \ - memcpy(buf, ptr - tagbytes - 1, 16); \ - dst->data = buf + tagbytes + 1; \ - } else if (UPB_LIKELY(size <= 32)) { \ - if (UPB_UNLIKELY(common_has < 32)) goto longstr; \ - fastdecode_docopy(d, ptr, size, 32, buf, dst); \ - } else if (UPB_LIKELY(size <= 64)) { \ - if (UPB_UNLIKELY(common_has < 64)) goto longstr; \ - fastdecode_docopy(d, ptr, size, 64, buf, dst); \ - } else if (UPB_LIKELY(size < 128)) { \ - if (UPB_UNLIKELY(common_has < 128)) goto longstr; \ - fastdecode_docopy(d, ptr, size, 128, buf, dst); \ - } else { \ - goto longstr; \ - } \ - \ - ptr += size; \ - \ - if (card == CARD_r) { \ - if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8); \ - } \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView)); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - if (card != CARD_r && validate_utf8) { \ - data = (uint64_t)dst; \ - UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ - \ - longstr: \ - if (card == CARD_r) { \ - fastdecode_commitarr(dst + 1, &farr, sizeof(upb_StringView)); \ - } \ - ptr--; \ - if (validate_utf8) { \ - UPB_MUSTTAIL return fastdecode_longstring_utf8(d, ptr, msg, table, \ - hasbits, (uint64_t)dst); \ - } else { \ - UPB_MUSTTAIL return fastdecode_longstring_noutf8(d, ptr, msg, table, \ - hasbits, (uint64_t)dst); \ +static char* upb_MtDataEncoder_PutBase92Varint(upb_MtDataEncoder* e, char* ptr, + uint32_t val, int min, int max) { + int shift = _upb_Log2Ceiling(upb_FromBase92(max) - upb_FromBase92(min) + 1); + UPB_ASSERT(shift <= 6); + uint32_t mask = (1 << shift) - 1; + do { + uint32_t bits = val & mask; + ptr = upb_MtDataEncoder_Put(e, ptr, bits + upb_FromBase92(min)); + if (!ptr) return NULL; + val >>= shift; + } while (val); + return ptr; +} + +char* upb_MtDataEncoder_PutModifier(upb_MtDataEncoder* e, char* ptr, + uint64_t mod) { + if (mod) { + ptr = upb_MtDataEncoder_PutBase92Varint(e, ptr, mod, + kUpb_EncodedValue_MinModifier, + kUpb_EncodedValue_MaxModifier); } + return ptr; +} -#define FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, card, \ - copyfunc, validate_utf8) \ - upb_StringView* dst; \ - fastdecode_arr farr; \ - int64_t size; \ - \ - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ - RETURN_GENERIC("string field tag mismatch\n"); \ - } \ - \ - if (UPB_UNLIKELY((d->options & kUpb_DecodeOption_AliasString) == 0)) { \ - UPB_MUSTTAIL return copyfunc(UPB_PARSE_ARGS); \ - } \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ - sizeof(upb_StringView), card); \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView)); \ - } \ - \ - size = (int8_t)ptr[tagbytes]; \ - ptr += tagbytes + 1; \ - dst->data = ptr; \ - dst->size = size; \ - \ - if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->end))) { \ - ptr--; \ - if (validate_utf8) { \ - return fastdecode_longstring_utf8(d, ptr, msg, table, hasbits, \ - (uint64_t)dst); \ - } else { \ - return fastdecode_longstring_noutf8(d, ptr, msg, table, hasbits, \ - (uint64_t)dst); \ - } \ - } \ - \ - ptr += size; \ - \ - if (card == CARD_r) { \ - if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8); \ - } \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView)); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - if (UPB_UNLIKELY((d->options & kUpb_DecodeOption_AliasString) == 0)) { \ - /* Buffer flipped and we can't alias any more. Bounce to */ \ - /* copyfunc(), but via dispatch since we need to reload table */ \ - /* data also. */ \ - fastdecode_commitarr(dst, &farr, sizeof(upb_StringView)); \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - } \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - if (card != CARD_r && validate_utf8) { \ - data = (uint64_t)dst; \ - UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +char* upb_MtDataEncoder_StartMessage(upb_MtDataEncoder* e, char* ptr, + uint64_t msg_mod) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + in->state.msg_state.msg_modifiers = msg_mod; + in->state.msg_state.last_field_num = 0; + in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; + return upb_MtDataEncoder_PutModifier(e, ptr, msg_mod); +} + +char* upb_MtDataEncoder_PutField(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod) { + static const char kUpb_TypeToEncoded[] = { + [kUpb_FieldType_Double] = kUpb_EncodedType_Double, + [kUpb_FieldType_Float] = kUpb_EncodedType_Float, + [kUpb_FieldType_Int64] = kUpb_EncodedType_Int64, + [kUpb_FieldType_UInt64] = kUpb_EncodedType_UInt64, + [kUpb_FieldType_Int32] = kUpb_EncodedType_Int32, + [kUpb_FieldType_Fixed64] = kUpb_EncodedType_Fixed64, + [kUpb_FieldType_Fixed32] = kUpb_EncodedType_Fixed32, + [kUpb_FieldType_Bool] = kUpb_EncodedType_Bool, + [kUpb_FieldType_String] = kUpb_EncodedType_String, + [kUpb_FieldType_Group] = kUpb_EncodedType_Group, + [kUpb_FieldType_Message] = kUpb_EncodedType_Message, + [kUpb_FieldType_Bytes] = kUpb_EncodedType_Bytes, + [kUpb_FieldType_UInt32] = kUpb_EncodedType_UInt32, + [kUpb_FieldType_Enum] = kUpb_EncodedType_Enum, + [kUpb_FieldType_SFixed32] = kUpb_EncodedType_SFixed32, + [kUpb_FieldType_SFixed64] = kUpb_EncodedType_SFixed64, + [kUpb_FieldType_SInt32] = kUpb_EncodedType_SInt32, + [kUpb_FieldType_SInt64] = kUpb_EncodedType_SInt64, + }; + + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (field_num <= in->state.msg_state.last_field_num) return NULL; + if (in->state.msg_state.last_field_num + 1 != field_num) { + // Put skip. + UPB_ASSERT(field_num > in->state.msg_state.last_field_num); + uint32_t skip = field_num - in->state.msg_state.last_field_num; + ptr = upb_MtDataEncoder_PutBase92Varint( + e, ptr, skip, kUpb_EncodedValue_MinSkip, kUpb_EncodedValue_MaxSkip); + if (!ptr) return NULL; + } + in->state.msg_state.last_field_num = field_num; + + uint32_t encoded_modifiers = 0; + + // Put field type. + if (type == kUpb_FieldType_Enum && + !(field_mod & kUpb_FieldModifier_IsClosedEnum)) { + type = kUpb_FieldType_Int32; + } + + int encoded_type = kUpb_TypeToEncoded[type]; + if (field_mod & kUpb_FieldModifier_IsRepeated) { + // Repeated fields shift the type number up (unlike other modifiers which + // are bit flags). + encoded_type += kUpb_EncodedType_RepeatedBase; + + if (upb_IsTypePackable(type)) { + bool field_is_packed = field_mod & kUpb_FieldModifier_IsPacked; + bool default_is_packed = in->state.msg_state.msg_modifiers & + kUpb_MessageModifier_DefaultIsPacked; + if (field_is_packed != default_is_packed) { + encoded_modifiers |= kUpb_EncodedFieldModifier_FlipPacked; + } + } + } + ptr = upb_MtDataEncoder_Put(e, ptr, encoded_type); + if (!ptr) return NULL; + + if (field_mod & kUpb_FieldModifier_IsProto3Singular) { + encoded_modifiers |= kUpb_EncodedFieldModifier_IsProto3Singular; + } + if (field_mod & kUpb_FieldModifier_IsRequired) { + encoded_modifiers |= kUpb_EncodedFieldModifier_IsRequired; + } + return upb_MtDataEncoder_PutModifier(e, ptr, encoded_modifiers); +} + +char* upb_MtDataEncoder_StartOneof(upb_MtDataEncoder* e, char* ptr) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (in->state.msg_state.oneof_state == kUpb_OneofState_NotStarted) { + ptr = upb_MtDataEncoder_Put(e, ptr, upb_FromBase92(kUpb_EncodedValue_End)); + } else { + ptr = upb_MtDataEncoder_Put( + e, ptr, upb_FromBase92(kUpb_EncodedValue_OneofSeparator)); + } + in->state.msg_state.oneof_state = kUpb_OneofState_StartedOneof; + return ptr; +} + +char* upb_MtDataEncoder_PutOneofField(upb_MtDataEncoder* e, char* ptr, + uint32_t field_num) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (in->state.msg_state.oneof_state == kUpb_OneofState_EmittedOneofField) { + ptr = upb_MtDataEncoder_Put( + e, ptr, upb_FromBase92(kUpb_EncodedValue_FieldSeparator)); + if (!ptr) return NULL; + } + ptr = upb_MtDataEncoder_PutBase92Varint(e, ptr, field_num, upb_ToBase92(0), + upb_ToBase92(63)); + in->state.msg_state.oneof_state = kUpb_OneofState_EmittedOneofField; + return ptr; +} + +void upb_MtDataEncoder_StartEnum(upb_MtDataEncoder* e) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, NULL); + in->state.enum_state.present_values_mask = 0; + in->state.enum_state.last_written_value = 0; +} + +static char* upb_MtDataEncoder_FlushDenseEnumMask(upb_MtDataEncoder* e, + char* ptr) { + upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; + ptr = upb_MtDataEncoder_Put(e, ptr, in->state.enum_state.present_values_mask); + in->state.enum_state.present_values_mask = 0; + in->state.enum_state.last_written_value += 5; + return ptr; +} + +char* upb_MtDataEncoder_PutEnumValue(upb_MtDataEncoder* e, char* ptr, + uint32_t val) { + // TODO(b/229641772): optimize this encoding. + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + UPB_ASSERT(val >= in->state.enum_state.last_written_value); + uint32_t delta = val - in->state.enum_state.last_written_value; + if (delta >= 5 && in->state.enum_state.present_values_mask) { + ptr = upb_MtDataEncoder_FlushDenseEnumMask(e, ptr); + if (!ptr) { + return NULL; + } + delta -= 5; + } + + if (delta >= 5) { + ptr = upb_MtDataEncoder_PutBase92Varint( + e, ptr, delta, kUpb_EncodedValue_MinSkip, kUpb_EncodedValue_MaxSkip); + in->state.enum_state.last_written_value += delta; + delta = 0; + } + + UPB_ASSERT((in->state.enum_state.present_values_mask >> delta) == 0); + in->state.enum_state.present_values_mask |= 1ULL << delta; + return ptr; +} + +char* upb_MtDataEncoder_EndEnum(upb_MtDataEncoder* e, char* ptr) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (!in->state.enum_state.present_values_mask) return ptr; + return upb_MtDataEncoder_FlushDenseEnumMask(e, ptr); +} + +const upb_MiniTable_Field* upb_MiniTable_FindFieldByNumber( + const upb_MiniTable* table, uint32_t number) { + int n = table->field_count; + for (int i = 0; i < n; i++) { + if (table->fields[i].number == number) { + return &table->fields[i]; + } + } + return NULL; +} + +/** Data decoder **************************************************************/ + +// Note: we sort by this number when calculating layout order. +typedef enum { + kUpb_LayoutItemType_OneofCase, // Oneof case. + kUpb_LayoutItemType_OneofField, // Oneof field data. + kUpb_LayoutItemType_Field, // Non-oneof field data. + + kUpb_LayoutItemType_Max = kUpb_LayoutItemType_Field, +} upb_LayoutItemType; + +#define kUpb_LayoutItem_IndexSentinel ((uint16_t)-1) + +typedef struct { + // Index of the corresponding field. When this is a oneof field, the field's + // offset will be the index of the next field in a linked list. + uint16_t field_index; + uint16_t offset; + upb_FieldRep rep; + upb_LayoutItemType type; +} upb_LayoutItem; + +typedef struct { + upb_LayoutItem* data; + size_t size; + size_t capacity; +} upb_LayoutItemVector; + +typedef struct { + const char* end; + upb_MiniTable* table; + upb_MiniTable_Field* fields; + upb_MiniTablePlatform platform; + upb_LayoutItemVector vec; + upb_Arena* arena; + upb_Status* status; + + // When building enums. + upb_MiniTable_Enum* enum_table; + uint32_t enum_value_count; + uint32_t enum_data_count; + uint32_t enum_data_capacity; + + jmp_buf err; +} upb_MtDecoder; + +UPB_PRINTF(2, 3) +UPB_NORETURN static void upb_MtDecoder_ErrorFormat(upb_MtDecoder* d, + const char* fmt, ...) { + va_list argp; + upb_Status_SetErrorMessage(d->status, "Error building mini table: "); + va_start(argp, fmt); + upb_Status_VAppendErrorFormat(d->status, fmt, argp); + va_end(argp); + UPB_LONGJMP(d->err, 1); +} + +static void upb_MtDecoder_CheckOutOfMemory(upb_MtDecoder* d, const void* ptr) { + if (!ptr) upb_MtDecoder_ErrorFormat(d, "Out of memory"); +} + +// In each field's offset, we temporarily store a presence classifier: +enum PresenceClass { + kNoPresence = 0, + kHasbitPresence = 1, + kRequiredPresence = 2, + kOneofBase = 3, + // Negative values refer to a specific oneof with that number. Positive + // values >= kOneofBase indicate that this field is in a oneof, and specify + // the next field in this oneof's linked list. +}; + +static const char* upb_MiniTable_DecodeBase92Varint(upb_MtDecoder* d, + const char* ptr, + char first_ch, uint8_t min, + uint8_t max, + uint32_t* out_val) { + uint32_t val = 0; + uint32_t shift = 0; + const int bits_per_char = + _upb_Log2Ceiling(upb_FromBase92(max) - upb_FromBase92(min)); + char ch = first_ch; + while (1) { + uint32_t bits = upb_FromBase92(ch) - upb_FromBase92(min); + val |= bits << shift; + if (ptr == d->end || *ptr < min || max < *ptr) { + *out_val = val; + return ptr; + } + ch = *ptr++; + shift += bits_per_char; + if (shift >= 32) upb_MtDecoder_ErrorFormat(d, "Overlong varint"); + } +} + +static bool upb_MiniTable_HasSub(upb_MiniTable_Field* field, + uint64_t msg_modifiers) { + switch (field->descriptortype) { + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + case kUpb_FieldType_Enum: + return true; + case kUpb_FieldType_String: + if (!(msg_modifiers & kUpb_MessageModifier_ValidateUtf8)) { + field->descriptortype = kUpb_FieldType_Bytes; + } + return false; + default: + return false; + } +} -/* Generate all combinations: - * {p,c} x {s,o,r} x {s, b} x {1bt,2bt} */ +static bool upb_MtDecoder_FieldIsPackable(upb_MiniTable_Field* field) { + return (field->mode & kUpb_FieldMode_Array) && + upb_IsTypePackable(field->descriptortype); +} -#define s_VALIDATE true -#define b_VALIDATE false +static void upb_MiniTable_SetTypeAndSub(upb_MiniTable_Field* field, + upb_FieldType type, uint32_t* sub_count, + uint64_t msg_modifiers) { + field->descriptortype = type; + if (upb_MiniTable_HasSub(field, msg_modifiers)) { + field->submsg_index = sub_count ? (*sub_count)++ : 0; + } else { + field->submsg_index = kUpb_NoSub; + } -#define F(card, tagbytes, type) \ - UPB_NOINLINE \ - const char* upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ - CARD_##card, type##_VALIDATE); \ - } \ - const char* upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, \ - CARD_##card, upb_c##card##type##_##tagbytes##bt, \ - type##_VALIDATE); \ + if (upb_MtDecoder_FieldIsPackable(field) && + (msg_modifiers & kUpb_MessageModifier_DefaultIsPacked)) { + field->mode |= kUpb_LabelFlags_IsPacked; } +} -#define UTF8(card, tagbytes) \ - F(card, tagbytes, s) \ - F(card, tagbytes, b) +static void upb_MiniTable_SetField(upb_MtDecoder* d, uint8_t ch, + upb_MiniTable_Field* field, + uint64_t msg_modifiers, + uint32_t* sub_count) { + static const char kUpb_EncodedToFieldRep[] = { + [kUpb_EncodedType_Double] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Float] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Int64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_UInt64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Int32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Fixed64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Fixed32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Bool] = kUpb_FieldRep_1Byte, + [kUpb_EncodedType_String] = kUpb_FieldRep_StringView, + [kUpb_EncodedType_Group] = kUpb_FieldRep_Pointer, + [kUpb_EncodedType_Message] = kUpb_FieldRep_Pointer, + [kUpb_EncodedType_Bytes] = kUpb_FieldRep_StringView, + [kUpb_EncodedType_UInt32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Enum] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SFixed32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SFixed64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_SInt32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SInt64] = kUpb_FieldRep_8Byte, + }; -#define TAGBYTES(card) \ - UTF8(card, 1) \ - UTF8(card, 2) + static const char kUpb_EncodedToType[] = { + [kUpb_EncodedType_Double] = kUpb_FieldType_Double, + [kUpb_EncodedType_Float] = kUpb_FieldType_Float, + [kUpb_EncodedType_Int64] = kUpb_FieldType_Int64, + [kUpb_EncodedType_UInt64] = kUpb_FieldType_UInt64, + [kUpb_EncodedType_Int32] = kUpb_FieldType_Int32, + [kUpb_EncodedType_Fixed64] = kUpb_FieldType_Fixed64, + [kUpb_EncodedType_Fixed32] = kUpb_FieldType_Fixed32, + [kUpb_EncodedType_Bool] = kUpb_FieldType_Bool, + [kUpb_EncodedType_String] = kUpb_FieldType_String, + [kUpb_EncodedType_Group] = kUpb_FieldType_Group, + [kUpb_EncodedType_Message] = kUpb_FieldType_Message, + [kUpb_EncodedType_Bytes] = kUpb_FieldType_Bytes, + [kUpb_EncodedType_UInt32] = kUpb_FieldType_UInt32, + [kUpb_EncodedType_Enum] = kUpb_FieldType_Enum, + [kUpb_EncodedType_SFixed32] = kUpb_FieldType_SFixed32, + [kUpb_EncodedType_SFixed64] = kUpb_FieldType_SFixed64, + [kUpb_EncodedType_SInt32] = kUpb_FieldType_SInt32, + [kUpb_EncodedType_SInt64] = kUpb_FieldType_SInt64, + }; -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) + int8_t type = upb_FromBase92(ch); + if (ch >= upb_ToBase92(kUpb_EncodedType_RepeatedBase)) { + type -= kUpb_EncodedType_RepeatedBase; + field->mode = kUpb_FieldMode_Array; + field->mode |= kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift; + field->offset = kNoPresence; + } else { + if (type >= sizeof(kUpb_EncodedToFieldRep)) { + upb_MtDecoder_ErrorFormat(d, "Invalid field type: %d", (int)type); + UPB_UNREACHABLE(); + } + field->mode = kUpb_FieldMode_Scalar; + field->mode |= kUpb_EncodedToFieldRep[type] << kUpb_FieldRep_Shift; + field->offset = kHasbitPresence; + } + if (type >= sizeof(kUpb_EncodedToType)) { + upb_MtDecoder_ErrorFormat(d, "Invalid field type: %d", (int)type); + UPB_UNREACHABLE(); + } + upb_MiniTable_SetTypeAndSub(field, kUpb_EncodedToType[type], sub_count, + msg_modifiers); +} -#undef s_VALIDATE -#undef b_VALIDATE -#undef F -#undef TAGBYTES -#undef FASTDECODE_LONGSTRING -#undef FASTDECODE_COPYSTRING -#undef FASTDECODE_STRING +static void upb_MtDecoder_ModifyField(upb_MtDecoder* d, + uint32_t message_modifiers, + uint32_t field_modifiers, + upb_MiniTable_Field* field) { + if (field_modifiers & kUpb_EncodedFieldModifier_FlipPacked) { + if (!upb_MtDecoder_FieldIsPackable(field)) { + upb_MtDecoder_ErrorFormat( + d, "Cannot flip packed on unpackable field %" PRIu32, field->number); + UPB_UNREACHABLE(); + } + field->mode ^= kUpb_LabelFlags_IsPacked; + } -/* message fields *************************************************************/ + bool singular = field_modifiers & kUpb_EncodedFieldModifier_IsProto3Singular; + bool required = field_modifiers & kUpb_EncodedFieldModifier_IsRequired; -UPB_INLINE -upb_Message* decode_newmsg_ceil(upb_Decoder* d, const upb_MiniTable* l, - int msg_ceil_bytes) { - size_t size = l->size + sizeof(upb_Message_Internal); - char* msg_data; - if (UPB_LIKELY(msg_ceil_bytes > 0 && - _upb_ArenaHas(&d->arena) >= msg_ceil_bytes)) { - UPB_ASSERT(size <= (size_t)msg_ceil_bytes); - msg_data = d->arena.head.ptr; - d->arena.head.ptr += size; - UPB_UNPOISON_MEMORY_REGION(msg_data, msg_ceil_bytes); - memset(msg_data, 0, msg_ceil_bytes); - UPB_POISON_MEMORY_REGION(msg_data + size, msg_ceil_bytes - size); + // Validate. + if ((singular || required) && field->offset != kHasbitPresence) { + upb_MtDecoder_ErrorFormat( + d, "Invalid modifier(s) for repeated field %" PRIu32, field->number); + UPB_UNREACHABLE(); + } + if (singular && required) { + upb_MtDecoder_ErrorFormat( + d, "Field %" PRIu32 " cannot be both singular and required", + field->number); + UPB_UNREACHABLE(); + } + + if (singular) field->offset = kNoPresence; + if (required) { + field->offset = kRequiredPresence; + } +} + +static void upb_MtDecoder_PushItem(upb_MtDecoder* d, upb_LayoutItem item) { + if (d->vec.size == d->vec.capacity) { + size_t new_cap = UPB_MAX(8, d->vec.size * 2); + d->vec.data = realloc(d->vec.data, new_cap * sizeof(*d->vec.data)); + upb_MtDecoder_CheckOutOfMemory(d, d->vec.data); + d->vec.capacity = new_cap; + } + d->vec.data[d->vec.size++] = item; +} + +static void upb_MtDecoder_PushOneof(upb_MtDecoder* d, upb_LayoutItem item) { + if (item.field_index == kUpb_LayoutItem_IndexSentinel) { + upb_MtDecoder_ErrorFormat(d, "Empty oneof"); + UPB_UNREACHABLE(); + } + item.field_index -= kOneofBase; + + // Push oneof data. + item.type = kUpb_LayoutItemType_OneofField; + upb_MtDecoder_PushItem(d, item); + + // Push oneof case. + item.rep = kUpb_FieldRep_4Byte; // Field Number. + item.type = kUpb_LayoutItemType_OneofCase; + upb_MtDecoder_PushItem(d, item); +} + +size_t upb_MtDecoder_SizeOfRep(upb_FieldRep rep, + upb_MiniTablePlatform platform) { + static const uint8_t kRepToSize32[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 4, [kUpb_FieldRep_StringView] = 8, + [kUpb_FieldRep_8Byte] = 8, + }; + static const uint8_t kRepToSize64[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 8, [kUpb_FieldRep_StringView] = 16, + [kUpb_FieldRep_8Byte] = 8, + }; + UPB_ASSERT(sizeof(upb_StringView) == + UPB_SIZE(kRepToSize32, kRepToSize64)[kUpb_FieldRep_StringView]); + return platform == kUpb_MiniTablePlatform_32Bit ? kRepToSize32[rep] + : kRepToSize64[rep]; +} + +size_t upb_MtDecoder_AlignOfRep(upb_FieldRep rep, + upb_MiniTablePlatform platform) { + static const uint8_t kRepToAlign32[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 4, [kUpb_FieldRep_StringView] = 4, + [kUpb_FieldRep_8Byte] = 8, + }; + static const uint8_t kRepToAlign64[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 8, [kUpb_FieldRep_StringView] = 8, + [kUpb_FieldRep_8Byte] = 8, + }; + UPB_ASSERT(UPB_ALIGN_OF(upb_StringView) == + UPB_SIZE(kRepToAlign32, kRepToAlign64)[kUpb_FieldRep_StringView]); + return platform == kUpb_MiniTablePlatform_32Bit ? kRepToAlign32[rep] + : kRepToAlign64[rep]; +} + +static const char* upb_MtDecoder_DecodeOneofField(upb_MtDecoder* d, + const char* ptr, + char first_ch, + upb_LayoutItem* item) { + uint32_t field_num; + ptr = upb_MiniTable_DecodeBase92Varint( + d, ptr, first_ch, kUpb_EncodedValue_MinOneofField, + kUpb_EncodedValue_MaxOneofField, &field_num); + upb_MiniTable_Field* f = + (void*)upb_MiniTable_FindFieldByNumber(d->table, field_num); + + if (!f) { + upb_MtDecoder_ErrorFormat(d, + "Couldn't add field number %" PRIu32 + " to oneof, no such field number.", + field_num); + UPB_UNREACHABLE(); + } + if (f->offset != kHasbitPresence) { + upb_MtDecoder_ErrorFormat( + d, + "Cannot add repeated, required, or singular field %" PRIu32 + " to oneof.", + field_num); + UPB_UNREACHABLE(); + } + + // Oneof storage must be large enough to accommodate the largest member. + int rep = f->mode >> kUpb_FieldRep_Shift; + if (upb_MtDecoder_SizeOfRep(rep, d->platform) > + upb_MtDecoder_SizeOfRep(item->rep, d->platform)) { + item->rep = rep; + } + // Prepend this field to the linked list. + f->offset = item->field_index; + item->field_index = (f - d->fields) + kOneofBase; + return ptr; +} + +static const char* upb_MtDecoder_DecodeOneofs(upb_MtDecoder* d, + const char* ptr) { + upb_LayoutItem item = {.rep = 0, + .field_index = kUpb_LayoutItem_IndexSentinel}; + while (ptr < d->end) { + char ch = *ptr++; + if (ch == kUpb_EncodedValue_FieldSeparator) { + // Field separator, no action needed. + } else if (ch == kUpb_EncodedValue_OneofSeparator) { + // End of oneof. + upb_MtDecoder_PushOneof(d, item); + item.field_index = kUpb_LayoutItem_IndexSentinel; // Move to next oneof. + } else { + ptr = upb_MtDecoder_DecodeOneofField(d, ptr, ch, &item); + } + } + + // Push final oneof. + upb_MtDecoder_PushOneof(d, item); + return ptr; +} + +static const char* upb_MtDecoder_ParseModifier(upb_MtDecoder* d, + const char* ptr, char first_ch, + upb_MiniTable_Field* last_field, + uint64_t* msg_modifiers) { + uint32_t mod; + ptr = upb_MiniTable_DecodeBase92Varint(d, ptr, first_ch, + kUpb_EncodedValue_MinModifier, + kUpb_EncodedValue_MaxModifier, &mod); + if (last_field) { + upb_MtDecoder_ModifyField(d, *msg_modifiers, mod, last_field); } else { - msg_data = (char*)upb_Arena_Malloc(&d->arena, size); - memset(msg_data, 0, size); + if (!d->table) { + upb_MtDecoder_ErrorFormat(d, "Extensions cannot have message modifiers"); + UPB_UNREACHABLE(); + } + *msg_modifiers = mod; } - return msg_data + sizeof(upb_Message_Internal); + + return ptr; } -typedef struct { - intptr_t table; - upb_Message* msg; -} fastdecode_submsgdata; +static void upb_MtDecoder_AllocateSubs(upb_MtDecoder* d, uint32_t sub_count) { + size_t subs_bytes = sizeof(*d->table->subs) * sub_count; + d->table->subs = upb_Arena_Malloc(d->arena, subs_bytes); + upb_MtDecoder_CheckOutOfMemory(d, d->table->subs); +} + +static const char* upb_MtDecoder_Parse(upb_MtDecoder* d, const char* ptr, + size_t len, void* fields, + size_t field_size, uint16_t* field_count, + uint32_t* sub_count) { + uint64_t msg_modifiers = 0; + uint32_t last_field_number = 0; + upb_MiniTable_Field* last_field = NULL; + bool need_dense_below = d->table != NULL; + + d->end = UPB_PTRADD(ptr, len); + + while (ptr < d->end) { + char ch = *ptr++; + if (ch <= kUpb_EncodedValue_MaxField) { + if (!d->table && last_field) { + // For extensions, consume only a single field and then return. + return --ptr; + } + upb_MiniTable_Field* field = fields; + *field_count += 1; + fields = (char*)fields + field_size; + field->number = ++last_field_number; + last_field = field; + upb_MiniTable_SetField(d, ch, field, msg_modifiers, sub_count); + } else if (kUpb_EncodedValue_MinModifier <= ch && + ch <= kUpb_EncodedValue_MaxModifier) { + ptr = upb_MtDecoder_ParseModifier(d, ptr, ch, last_field, &msg_modifiers); + if (msg_modifiers & kUpb_MessageModifier_IsExtendable) { + d->table->ext |= kUpb_ExtMode_Extendable; + } + } else if (ch == kUpb_EncodedValue_End) { + if (!d->table) { + upb_MtDecoder_ErrorFormat(d, "Extensions cannot have oneofs."); + UPB_UNREACHABLE(); + } + ptr = upb_MtDecoder_DecodeOneofs(d, ptr); + } else if (kUpb_EncodedValue_MinSkip <= ch && + ch <= kUpb_EncodedValue_MaxSkip) { + if (need_dense_below) { + d->table->dense_below = d->table->field_count; + need_dense_below = false; + } + uint32_t skip; + ptr = upb_MiniTable_DecodeBase92Varint(d, ptr, ch, + kUpb_EncodedValue_MinSkip, + kUpb_EncodedValue_MaxSkip, &skip); + last_field_number += skip; + last_field_number--; // Next field seen will increment. + } + } + + if (need_dense_below) { + d->table->dense_below = d->table->field_count; + } -UPB_FORCEINLINE -static const char* fastdecode_tosubmsg(upb_Decoder* d, const char* ptr, - void* ctx) { - fastdecode_submsgdata* submsg = ctx; - ptr = fastdecode_dispatch(d, ptr, submsg->msg, submsg->table, 0, 0); - UPB_ASSUME(ptr != NULL); return ptr; } -#define FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, \ - msg_ceil_bytes, card) \ - \ - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ - RETURN_GENERIC("submessage field tag mismatch\n"); \ - } \ - \ - if (--d->depth == 0) { \ - return fastdecode_err(d, kUpb_DecodeStatus_MaxDepthExceeded); \ - } \ - \ - upb_Message** dst; \ - uint32_t submsg_idx = (data >> 16) & 0xff; \ - const upb_MiniTable* tablep = decode_totablep(table); \ - const upb_MiniTable* subtablep = tablep->subs[submsg_idx].submsg; \ - fastdecode_submsgdata submsg = {decode_totable(subtablep)}; \ - fastdecode_arr farr; \ - \ - if (subtablep->table_mask == (uint8_t)-1) { \ - RETURN_GENERIC("submessage doesn't have fast tables."); \ - } \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ - sizeof(upb_Message*), card); \ - \ - if (card == CARD_s) { \ - *(uint32_t*)msg |= hasbits; \ - hasbits = 0; \ - } \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_Message*)); \ - } \ - \ - submsg.msg = *dst; \ - \ - if (card == CARD_r || UPB_LIKELY(!submsg.msg)) { \ - *dst = submsg.msg = decode_newmsg_ceil(d, subtablep, msg_ceil_bytes); \ - } \ - \ - ptr += tagbytes; \ - ptr = fastdecode_delimited(d, ptr, fastdecode_tosubmsg, &submsg); \ - \ - if (UPB_UNLIKELY(ptr == NULL || d->end_group != DECODE_NOGROUP)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - \ - if (card == CARD_r) { \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_Message*)); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - d->depth++; \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - d->depth++; \ - return ptr; \ - } \ - } \ - \ - d->depth++; \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +static void upb_MtDecoder_ParseMessage(upb_MtDecoder* d, const char* data, + size_t len) { + // Buffer length is an upper bound on the number of fields. We will return + // what we don't use. + d->fields = upb_Arena_Malloc(d->arena, sizeof(*d->fields) * len); + upb_MtDecoder_CheckOutOfMemory(d, d->fields); + + uint32_t sub_count = 0; + d->table->field_count = 0; + d->table->fields = d->fields; + upb_MtDecoder_Parse(d, data, len, d->fields, sizeof(*d->fields), + &d->table->field_count, &sub_count); + + upb_Arena_ShrinkLast(d->arena, d->fields, sizeof(*d->fields) * len, + sizeof(*d->fields) * d->table->field_count); + d->table->fields = d->fields; + upb_MtDecoder_AllocateSubs(d, sub_count); +} + +int upb_MtDecoder_CompareFields(const void* _a, const void* _b) { + const upb_LayoutItem* a = _a; + const upb_LayoutItem* b = _b; + // Currently we just sort by: + // 1. rep (smallest fields first) + // 2. type (oneof cases first) + // 2. field_index (smallest numbers first) + // The main goal of this is to reduce space lost to padding. + // Later we may have more subtle reasons to prefer a different ordering. + const int rep_bits = _upb_Log2Ceiling(kUpb_FieldRep_Max); + const int type_bits = _upb_Log2Ceiling(kUpb_LayoutItemType_Max); + const int idx_bits = (sizeof(a->field_index) * 8); + UPB_ASSERT(idx_bits + rep_bits + type_bits < 32); +#define UPB_COMBINE(rep, ty, idx) (((rep << type_bits) | ty) << idx_bits) | idx + uint32_t a_packed = UPB_COMBINE(a->rep, a->type, a->field_index); + uint32_t b_packed = UPB_COMBINE(b->rep, b->type, b->field_index); + assert(a_packed != b_packed); +#undef UPB_COMBINE + return a_packed < b_packed ? -1 : 1; +} + +static bool upb_MtDecoder_SortLayoutItems(upb_MtDecoder* d) { + // Add items for all non-oneof fields (oneofs were already added). + int n = d->table->field_count; + for (int i = 0; i < n; i++) { + upb_MiniTable_Field* f = &d->fields[i]; + if (f->offset >= kOneofBase) continue; + upb_LayoutItem item = {.field_index = i, + .rep = f->mode >> kUpb_FieldRep_Shift, + .type = kUpb_LayoutItemType_Field}; + upb_MtDecoder_PushItem(d, item); + } -#define F(card, tagbytes, size_ceil, ceil_arg) \ - const char* upb_p##card##m_##tagbytes##bt_max##size_ceil##b( \ - UPB_PARSE_PARAMS) { \ - FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, ceil_arg, \ - CARD_##card); \ + if (d->vec.size) { + qsort(d->vec.data, d->vec.size, sizeof(*d->vec.data), + upb_MtDecoder_CompareFields); } -#define SIZES(card, tagbytes) \ - F(card, tagbytes, 64, 64) \ - F(card, tagbytes, 128, 128) \ - F(card, tagbytes, 192, 192) \ - F(card, tagbytes, 256, 256) \ - F(card, tagbytes, max, -1) + return true; +} -#define TAGBYTES(card) \ - SIZES(card, 1) \ - SIZES(card, 2) +static size_t upb_MiniTable_DivideRoundUp(size_t n, size_t d) { + return (n + d - 1) / d; +} -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) +static void upb_MtDecoder_AssignHasbits(upb_MiniTable* ret) { + int n = ret->field_count; + int last_hasbit = 0; // 0 cannot be used. -#undef TAGBYTES -#undef SIZES -#undef F -#undef FASTDECODE_SUBMSG + // First assign required fields, which must have the lowest hasbits. + for (int i = 0; i < n; i++) { + upb_MiniTable_Field* field = (upb_MiniTable_Field*)&ret->fields[i]; + if (field->offset == kRequiredPresence) { + field->presence = ++last_hasbit; + } else if (field->offset == kNoPresence) { + field->presence = 0; + } + } + ret->required_count = last_hasbit; -#endif /* UPB_FASTTABLE */ + // Next assign non-required hasbit fields. + for (int i = 0; i < n; i++) { + upb_MiniTable_Field* field = (upb_MiniTable_Field*)&ret->fields[i]; + if (field->offset == kHasbitPresence) { + field->presence = ++last_hasbit; + } + } -/** bazel-out/k8-fastbuild/bin/external/com_google_protobuf/google/protobuf/descriptor.upb.c ************************************************************//* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/descriptor.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ + ret->size = last_hasbit ? upb_MiniTable_DivideRoundUp(last_hasbit + 1, 8) : 0; +} + +size_t upb_MtDecoder_Place(upb_MtDecoder* d, upb_FieldRep rep) { + size_t size = upb_MtDecoder_SizeOfRep(rep, d->platform); + size_t align = upb_MtDecoder_AlignOfRep(rep, d->platform); + size_t ret = UPB_ALIGN_UP(d->table->size, align); + static const size_t max = UINT16_MAX; + size_t new_size = ret + size; + if (new_size > max) { + upb_MtDecoder_ErrorFormat( + d, "Message size exceeded maximum size of %zu bytes", max); + } + d->table->size = new_size; + return ret; +} + +static void upb_MtDecoder_AssignOffsets(upb_MtDecoder* d) { + upb_LayoutItem* end = UPB_PTRADD(d->vec.data, d->vec.size); + + // Compute offsets. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + item->offset = upb_MtDecoder_Place(d, item->rep); + } + + // Assign oneof case offsets. We must do these first, since assigning + // actual offsets will overwrite the links of the linked list. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + if (item->type != kUpb_LayoutItemType_OneofCase) continue; + upb_MiniTable_Field* f = &d->fields[item->field_index]; + while (true) { + f->presence = ~item->offset; + if (f->offset == kUpb_LayoutItem_IndexSentinel) break; + UPB_ASSERT(f->offset - kOneofBase < d->table->field_count); + f = &d->fields[f->offset - kOneofBase]; + } + } + + // Assign offsets. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + upb_MiniTable_Field* f = &d->fields[item->field_index]; + switch (item->type) { + case kUpb_LayoutItemType_OneofField: + while (true) { + uint16_t next_offset = f->offset; + f->offset = item->offset; + if (next_offset == kUpb_LayoutItem_IndexSentinel) break; + f = &d->fields[next_offset - kOneofBase]; + } + break; + case kUpb_LayoutItemType_Field: + f->offset = item->offset; + break; + default: + break; + } + } + + // The fasttable parser (supported on 64-bit only) depends on this being a + // multiple of 8 in order to satisfy UPB_MALLOC_ALIGN, which is also 8. + // + // On 32-bit we could potentially make this smaller, but there is no + // compelling reason to optimize this right now. + d->table->size = UPB_ALIGN_UP(d->table->size, 8); +} + +upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, void** buf, + size_t* buf_size, + upb_Status* status) { + upb_MtDecoder decoder = { + .platform = platform, + .vec = + { + .data = *buf, + .capacity = *buf_size / sizeof(*decoder.vec.data), + .size = 0, + }, + .arena = arena, + .status = status, + .table = upb_Arena_Malloc(arena, sizeof(*decoder.table)), + }; -#include + if (UPB_SETJMP(decoder.err)) { + decoder.table = NULL; + goto done; + } + upb_MtDecoder_CheckOutOfMemory(&decoder, decoder.table); -static const upb_MiniTable_Sub google_protobuf_FileDescriptorSet_submsgs[1] = { - {.submsg = &google_protobuf_FileDescriptorProto_msginit}, -}; + decoder.table->size = 0; + decoder.table->field_count = 0; + decoder.table->ext = kUpb_ExtMode_NonExtendable; + decoder.table->dense_below = 0; + decoder.table->table_mask = -1; + decoder.table->required_count = 0; -static const upb_MiniTable_Field google_protobuf_FileDescriptorSet__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; + upb_MtDecoder_ParseMessage(&decoder, data, len); + upb_MtDecoder_AssignHasbits(decoder.table); + upb_MtDecoder_SortLayoutItems(&decoder); + upb_MtDecoder_AssignOffsets(&decoder); -const upb_MiniTable google_protobuf_FileDescriptorSet_msginit = { - &google_protobuf_FileDescriptorSet_submsgs[0], - &google_protobuf_FileDescriptorSet__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, -}; +done: + *buf = decoder.vec.data; + *buf_size = decoder.vec.capacity * sizeof(*decoder.vec.data); + return decoder.table; +} + +upb_MiniTable* upb_MiniTable_BuildMessageSet(upb_MiniTablePlatform platform, + upb_Arena* arena) { + upb_MiniTable* ret = upb_Arena_Malloc(arena, sizeof(*ret)); + if (!ret) return NULL; + + ret->size = 0; + ret->field_count = 0; + ret->ext = kUpb_ExtMode_IsMessageSet; + ret->dense_below = 0; + ret->table_mask = -1; + ret->required_count = 0; + return ret; +} -static const upb_MiniTable_Sub google_protobuf_FileDescriptorProto_submsgs[6] = { - {.submsg = &google_protobuf_DescriptorProto_msginit}, - {.submsg = &google_protobuf_EnumDescriptorProto_msginit}, - {.submsg = &google_protobuf_FieldDescriptorProto_msginit}, - {.submsg = &google_protobuf_FileOptions_msginit}, - {.submsg = &google_protobuf_ServiceDescriptorProto_msginit}, - {.submsg = &google_protobuf_SourceCodeInfo_msginit}, -}; +upb_MiniTable* upb_MiniTable_BuildMapEntry(upb_FieldType key_type, + upb_FieldType value_type, + bool value_is_proto3_enum, + upb_MiniTablePlatform platform, + upb_Arena* arena) { + upb_MiniTable* ret = upb_Arena_Malloc(arena, sizeof(*ret)); + upb_MiniTable_Field* fields = upb_Arena_Malloc(arena, sizeof(*fields) * 2); + if (!ret || !fields) return NULL; + + upb_MiniTable_Sub* subs = NULL; + if (value_is_proto3_enum) value_type = kUpb_FieldType_Int32; + if (value_type == kUpb_FieldType_Message || + value_type == kUpb_FieldType_Group || value_type == kUpb_FieldType_Enum) { + subs = upb_Arena_Malloc(arena, sizeof(*subs)); + if (!subs) return NULL; + } + + size_t field_size = + upb_MtDecoder_SizeOfRep(kUpb_FieldRep_StringView, platform); + + fields[0].number = 1; + fields[1].number = 2; + fields[0].mode = kUpb_FieldMode_Scalar; + fields[1].mode = kUpb_FieldMode_Scalar; + fields[0].presence = 0; + fields[1].presence = 0; + fields[0].offset = 0; + fields[1].offset = field_size; + + upb_MiniTable_SetTypeAndSub(&fields[0], key_type, NULL, 0); + upb_MiniTable_SetTypeAndSub(&fields[1], value_type, NULL, 0); + + ret->size = UPB_ALIGN_UP(2 * field_size, 8); + ret->field_count = 2; + ret->ext = kUpb_ExtMode_NonExtendable | kUpb_ExtMode_IsMapEntry; + ret->dense_below = 2; + ret->table_mask = -1; + ret->required_count = 0; + ret->subs = subs; + ret->fields = fields; + return ret; +} -static const upb_MiniTable_Field google_protobuf_FileDescriptorProto__fields[12] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(36, 72), 0, 0, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(40, 80), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(44, 88), 0, 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(48, 96), 0, 4, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {7, UPB_SIZE(52, 104), 0, 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(28, 56), 3, 3, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {9, UPB_SIZE(32, 64), 4, 5, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {10, UPB_SIZE(56, 112), 0, 0, 5, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {11, UPB_SIZE(60, 120), 0, 0, 5, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {12, UPB_SIZE(20, 40), 5, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, -}; +static size_t upb_MiniTable_EnumSize(size_t count) { + return sizeof(upb_MiniTable_Enum) + count * sizeof(uint32_t); +} -const upb_MiniTable google_protobuf_FileDescriptorProto_msginit = { - &google_protobuf_FileDescriptorProto_submsgs[0], - &google_protobuf_FileDescriptorProto__fields[0], - UPB_SIZE(64, 128), 12, kUpb_ExtMode_NonExtendable, 12, 255, 0, -}; +static upb_MiniTable_Enum* _upb_MiniTable_AddEnumDataMember(upb_MtDecoder* d, + uint32_t val) { + if (d->enum_data_count == d->enum_data_capacity) { + size_t old_sz = upb_MiniTable_EnumSize(d->enum_data_capacity); + d->enum_data_capacity = UPB_MAX(2, d->enum_data_capacity * 2); + size_t new_sz = upb_MiniTable_EnumSize(d->enum_data_capacity); + d->enum_table = upb_Arena_Realloc(d->arena, d->enum_table, old_sz, new_sz); + upb_MtDecoder_CheckOutOfMemory(d, d->enum_table); + } + d->enum_table->data[d->enum_data_count++] = val; + return d->enum_table; +} -static const upb_MiniTable_Sub google_protobuf_DescriptorProto_submsgs[7] = { - {.submsg = &google_protobuf_DescriptorProto_msginit}, - {.submsg = &google_protobuf_DescriptorProto_ExtensionRange_msginit}, - {.submsg = &google_protobuf_DescriptorProto_ReservedRange_msginit}, - {.submsg = &google_protobuf_EnumDescriptorProto_msginit}, - {.submsg = &google_protobuf_FieldDescriptorProto_msginit}, - {.submsg = &google_protobuf_MessageOptions_msginit}, - {.submsg = &google_protobuf_OneofDescriptorProto_msginit}, -}; +static void upb_MiniTable_BuildEnumValue(upb_MtDecoder* d, uint32_t val) { + upb_MiniTable_Enum* table = d->enum_table; + d->enum_value_count++; + if (table->value_count || (val > 512 && d->enum_value_count < val / 32)) { + if (table->value_count == 0) { + assert(d->enum_data_count == table->mask_limit / 32); + } + table = _upb_MiniTable_AddEnumDataMember(d, val); + table->value_count++; + } else { + uint32_t new_mask_limit = ((val / 32) + 1) * 32; + while (table->mask_limit < new_mask_limit) { + table = _upb_MiniTable_AddEnumDataMember(d, 0); + table->mask_limit += 32; + } + table->data[val / 32] |= 1ULL << (val % 32); + } +} + +upb_MiniTable_Enum* upb_MiniTable_BuildEnum(const char* data, size_t len, + upb_Arena* arena, + upb_Status* status) { + upb_MtDecoder d = { + .enum_table = upb_Arena_Malloc(arena, upb_MiniTable_EnumSize(2)), + .enum_value_count = 0, + .enum_data_count = 0, + .enum_data_capacity = 1, + .status = status, + .end = UPB_PTRADD(data, len), + .arena = arena, + }; -static const upb_MiniTable_Field google_protobuf_DescriptorProto__fields[10] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(16, 32), 0, 4, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(20, 40), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(24, 48), 0, 3, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(28, 56), 0, 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(32, 64), 0, 4, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {7, UPB_SIZE(12, 24), 2, 5, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(36, 72), 0, 6, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {9, UPB_SIZE(40, 80), 0, 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {10, UPB_SIZE(44, 88), 0, 0, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; + if (UPB_SETJMP(d.err)) { + return NULL; + } -const upb_MiniTable google_protobuf_DescriptorProto_msginit = { - &google_protobuf_DescriptorProto_submsgs[0], - &google_protobuf_DescriptorProto__fields[0], - UPB_SIZE(48, 96), 10, kUpb_ExtMode_NonExtendable, 10, 255, 0, -}; + upb_MtDecoder_CheckOutOfMemory(&d, d.enum_table); -static const upb_MiniTable_Sub google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = { - {.submsg = &google_protobuf_ExtensionRangeOptions_msginit}, -}; + // Guarantee at least 64 bits of mask without checking mask size. + d.enum_table->mask_limit = 64; + d.enum_table = _upb_MiniTable_AddEnumDataMember(&d, 0); + d.enum_table = _upb_MiniTable_AddEnumDataMember(&d, 0); -static const upb_MiniTable_Field google_protobuf_DescriptorProto_ExtensionRange__fields[3] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 16), 3, 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; + d.enum_table->value_count = 0; -const upb_MiniTable google_protobuf_DescriptorProto_ExtensionRange_msginit = { - &google_protobuf_DescriptorProto_ExtensionRange_submsgs[0], - &google_protobuf_DescriptorProto_ExtensionRange__fields[0], - UPB_SIZE(16, 24), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, -}; + const char* ptr = data; + uint32_t base = 0; -static const upb_MiniTable_Field google_protobuf_DescriptorProto_ReservedRange__fields[2] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, -}; + while (ptr < d.end) { + char ch = *ptr++; + if (ch <= kUpb_EncodedValue_MaxEnumMask) { + uint32_t mask = upb_FromBase92(ch); + for (int i = 0; i < 5; i++, base++, mask >>= 1) { + if (mask & 1) upb_MiniTable_BuildEnumValue(&d, base); + } + } else if (kUpb_EncodedValue_MinSkip <= ch && + ch <= kUpb_EncodedValue_MaxSkip) { + uint32_t skip; + ptr = upb_MiniTable_DecodeBase92Varint(&d, ptr, ch, + kUpb_EncodedValue_MinSkip, + kUpb_EncodedValue_MaxSkip, &skip); + base += skip; + } else { + upb_Status_SetErrorFormat(status, "Unexpected character: %c", ch); + return NULL; + } + } -const upb_MiniTable google_protobuf_DescriptorProto_ReservedRange_msginit = { - NULL, - &google_protobuf_DescriptorProto_ReservedRange__fields[0], - UPB_SIZE(16, 16), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, -}; + return d.enum_table; +} -static const upb_MiniTable_Sub google_protobuf_ExtensionRangeOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; +const char* upb_MiniTable_BuildExtension(const char* data, size_t len, + upb_MiniTable_Extension* ext, + const upb_MiniTable* extendee, + upb_MiniTable_Sub sub, + upb_Status* status) { + upb_MtDecoder decoder = { + .arena = NULL, + .status = status, + .table = NULL, + }; -static const upb_MiniTable_Field google_protobuf_ExtensionRangeOptions__fields[1] = { - {999, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; + if (UPB_SETJMP(decoder.err)) { + return NULL; + } -const upb_MiniTable google_protobuf_ExtensionRangeOptions_msginit = { - &google_protobuf_ExtensionRangeOptions_submsgs[0], - &google_protobuf_ExtensionRangeOptions__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_Extendable, 0, 255, 0, -}; + uint16_t count = 0; + const char* ret = + upb_MtDecoder_Parse(&decoder, data, len, ext, sizeof(*ext), &count, NULL); + if (!ret || count != 1) return NULL; -static const upb_MiniTable_Sub google_protobuf_FieldDescriptorProto_submsgs[3] = { - {.submsg = &google_protobuf_FieldOptions_msginit}, - {.subenum = &google_protobuf_FieldDescriptorProto_Label_enuminit}, - {.subenum = &google_protobuf_FieldDescriptorProto_Type_enuminit}, -}; + upb_MiniTable_Field* f = &ext->field; -static const upb_MiniTable_Field google_protobuf_FieldDescriptorProto__fields[11] = { - {1, UPB_SIZE(24, 24), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(32, 40), 2, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 12), 3, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(4, 4), 4, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(8, 8), 5, 2, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(40, 56), 6, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {7, UPB_SIZE(48, 72), 7, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(64, 104), 8, 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {9, UPB_SIZE(16, 16), 9, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {10, UPB_SIZE(56, 88), 10, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {17, UPB_SIZE(20, 20), 11, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, -}; + f->mode |= kUpb_LabelFlags_IsExtension; + f->offset = 0; + f->presence = 0; -const upb_MiniTable google_protobuf_FieldDescriptorProto_msginit = { - &google_protobuf_FieldDescriptorProto_submsgs[0], - &google_protobuf_FieldDescriptorProto__fields[0], - UPB_SIZE(72, 112), 11, kUpb_ExtMode_NonExtendable, 10, 255, 0, -}; + if (extendee->ext & kUpb_ExtMode_IsMessageSet) { + // Extensions of MessageSet must be messages. + if (!upb_IsSubMessage(f)) return NULL; -static const upb_MiniTable_Sub google_protobuf_OneofDescriptorProto_submsgs[1] = { - {.submsg = &google_protobuf_OneofOptions_msginit}, -}; + // Extensions of MessageSet must be non-repeating. + if ((f->mode & kUpb_FieldMode_Mask) == kUpb_FieldMode_Array) return NULL; + } -static const upb_MiniTable_Field google_protobuf_OneofDescriptorProto__fields[2] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 24), 2, 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; + ext->extendee = extendee; + ext->sub = sub; -const upb_MiniTable google_protobuf_OneofDescriptorProto_msginit = { - &google_protobuf_OneofDescriptorProto_submsgs[0], - &google_protobuf_OneofDescriptorProto__fields[0], - UPB_SIZE(16, 32), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, -}; + return ret; +} -static const upb_MiniTable_Sub google_protobuf_EnumDescriptorProto_submsgs[3] = { - {.submsg = &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit}, - {.submsg = &google_protobuf_EnumOptions_msginit}, - {.submsg = &google_protobuf_EnumValueDescriptorProto_msginit}, -}; +upb_MiniTable* upb_MiniTable_Build(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, upb_Status* status) { + void* buf = NULL; + size_t size = 0; + upb_MiniTable* ret = upb_MiniTable_BuildWithBuf(data, len, platform, arena, + &buf, &size, status); + free(buf); + return ret; +} -static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto__fields[5] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(16, 32), 0, 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 24), 2, 1, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(20, 40), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(24, 48), 0, 0, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; +void upb_MiniTable_SetSubMessage(upb_MiniTable* table, + upb_MiniTable_Field* field, + const upb_MiniTable* sub) { + UPB_ASSERT((uintptr_t)table->fields <= (uintptr_t)field && + (uintptr_t)field < + (uintptr_t)(table->fields + table->field_count)); + if (sub->ext & kUpb_ExtMode_IsMapEntry) { + field->mode = + (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift) | kUpb_FieldMode_Map; + } + upb_MiniTable_Sub* table_sub = (void*)&table->subs[field->submsg_index]; + table_sub->submsg = sub; +} -const upb_MiniTable google_protobuf_EnumDescriptorProto_msginit = { - &google_protobuf_EnumDescriptorProto_submsgs[0], - &google_protobuf_EnumDescriptorProto__fields[0], - UPB_SIZE(32, 64), 5, kUpb_ExtMode_NonExtendable, 5, 255, 0, -}; +void upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTable_Field* field, + const upb_MiniTable_Enum* sub) { + UPB_ASSERT((uintptr_t)table->fields <= (uintptr_t)field && + (uintptr_t)field < + (uintptr_t)(table->fields + table->field_count)); + upb_MiniTable_Sub* table_sub = (void*)&table->subs[field->submsg_index]; + table_sub->subenum = sub; +} -static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, -}; -const upb_MiniTable google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit = { - NULL, - &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0], - UPB_SIZE(16, 16), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, -}; +#include -static const upb_MiniTable_Sub google_protobuf_EnumValueDescriptorProto_submsgs[1] = { - {.submsg = &google_protobuf_EnumValueOptions_msginit}, -}; -static const upb_MiniTable_Field google_protobuf_EnumValueDescriptorProto__fields[3] = { - {1, UPB_SIZE(8, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(4, 4), 2, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(16, 24), 3, 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; +// Must be last. -const upb_MiniTable google_protobuf_EnumValueDescriptorProto_msginit = { - &google_protobuf_EnumValueDescriptorProto_submsgs[0], - &google_protobuf_EnumValueDescriptorProto__fields[0], - UPB_SIZE(24, 32), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, -}; +/* The upb core does not generally have a concept of default instances. However + * for descriptor options we make an exception since the max size is known and + * modest (<200 bytes). All types can share a default instance since it is + * initialized to zeroes. + * + * We have to allocate an extra pointer for upb's internal metadata. */ +static const char opt_default_buf[_UPB_MAXOPT_SIZE + sizeof(void*)] = {0}; +const char* kUpbDefOptDefault = &opt_default_buf[sizeof(void*)]; -static const upb_MiniTable_Sub google_protobuf_ServiceDescriptorProto_submsgs[2] = { - {.submsg = &google_protobuf_MethodDescriptorProto_msginit}, - {.submsg = &google_protobuf_ServiceOptions_msginit}, -}; +const char* _upb_DefBuilder_FullToShort(const char* fullname) { + const char* p; -static const upb_MiniTable_Field google_protobuf_ServiceDescriptorProto__fields[3] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(16, 32), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 24), 2, 1, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; + if (fullname == NULL) { + return NULL; + } else if ((p = strrchr(fullname, '.')) == NULL) { + /* No '.' in the name, return the full string. */ + return fullname; + } else { + /* Return one past the last '.'. */ + return p + 1; + } +} -const upb_MiniTable google_protobuf_ServiceDescriptorProto_msginit = { - &google_protobuf_ServiceDescriptorProto_submsgs[0], - &google_protobuf_ServiceDescriptorProto__fields[0], - UPB_SIZE(24, 48), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, -}; +void _upb_DefBuilder_FailJmp(upb_DefBuilder* ctx) { UPB_LONGJMP(ctx->err, 1); } -static const upb_MiniTable_Sub google_protobuf_MethodDescriptorProto_submsgs[1] = { - {.submsg = &google_protobuf_MethodOptions_msginit}, -}; +void _upb_DefBuilder_Errf(upb_DefBuilder* ctx, const char* fmt, ...) { + va_list argp; + va_start(argp, fmt); + upb_Status_VSetErrorFormat(ctx->status, fmt, argp); + va_end(argp); + _upb_DefBuilder_FailJmp(ctx); +} -static const upb_MiniTable_Field google_protobuf_MethodDescriptorProto__fields[6] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(20, 40), 3, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(28, 56), 4, 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(1, 1), 5, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(2, 2), 6, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, -}; +void _upb_DefBuilder_OomErr(upb_DefBuilder* ctx) { + upb_Status_SetErrorMessage(ctx->status, "out of memory"); + _upb_DefBuilder_FailJmp(ctx); +} -const upb_MiniTable google_protobuf_MethodDescriptorProto_msginit = { - &google_protobuf_MethodDescriptorProto_submsgs[0], - &google_protobuf_MethodDescriptorProto__fields[0], - UPB_SIZE(32, 64), 6, kUpb_ExtMode_NonExtendable, 6, 255, 0, -}; +const char* _upb_DefBuilder_MakeFullName(upb_DefBuilder* ctx, + const char* prefix, + upb_StringView name) { + if (prefix) { + // ret = prefix + '.' + name; + size_t n = strlen(prefix); + char* ret = _upb_DefBuilder_Alloc(ctx, n + name.size + 2); + strcpy(ret, prefix); + ret[n] = '.'; + memcpy(&ret[n + 1], name.data, name.size); + ret[n + 1 + name.size] = '\0'; + return ret; + } else { + char* ret = upb_strdup2(name.data, name.size, ctx->arena); + if (!ret) _upb_DefBuilder_OomErr(ctx); + return ret; + } +} -static const upb_MiniTable_Sub google_protobuf_FileOptions_submsgs[2] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, - {.subenum = &google_protobuf_FileOptions_OptimizeMode_enuminit}, -}; +static bool remove_component(char* base, size_t* len) { + if (*len == 0) return false; -static const upb_MiniTable_Field google_protobuf_FileOptions__fields[21] = { - {1, UPB_SIZE(20, 24), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(28, 40), 2, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {9, UPB_SIZE(4, 4), 3, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {10, UPB_SIZE(8, 8), 4, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {11, UPB_SIZE(36, 56), 5, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {16, UPB_SIZE(9, 9), 6, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {17, UPB_SIZE(10, 10), 7, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {18, UPB_SIZE(11, 11), 8, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {20, UPB_SIZE(12, 12), 9, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {23, UPB_SIZE(13, 13), 10, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {27, UPB_SIZE(14, 14), 11, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {31, UPB_SIZE(15, 15), 12, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {36, UPB_SIZE(44, 72), 13, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {37, UPB_SIZE(52, 88), 14, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {39, UPB_SIZE(60, 104), 15, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {40, UPB_SIZE(68, 120), 16, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {41, UPB_SIZE(76, 136), 17, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {42, UPB_SIZE(16, 16), 18, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {44, UPB_SIZE(84, 152), 19, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {45, UPB_SIZE(92, 168), 20, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {999, UPB_SIZE(100, 184), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; + for (size_t i = *len - 1; i > 0; i--) { + if (base[i] == '.') { + *len = i; + return true; + } + } -const upb_MiniTable google_protobuf_FileOptions_msginit = { - &google_protobuf_FileOptions_submsgs[0], - &google_protobuf_FileOptions__fields[0], - UPB_SIZE(104, 192), 21, kUpb_ExtMode_Extendable, 1, 255, 0, -}; + *len = 0; + return true; +} -static const upb_MiniTable_Sub google_protobuf_MessageOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; +const void* _upb_DefBuilder_ResolveAny(upb_DefBuilder* ctx, + const char* from_name_dbg, + const char* base, upb_StringView sym, + upb_deftype_t* type) { + if (sym.size == 0) goto notfound; + upb_value v; + if (sym.data[0] == '.') { + /* Symbols starting with '.' are absolute, so we do a single lookup. + * Slice to omit the leading '.' */ + if (!_upb_DefPool_LookupSym(ctx->symtab, sym.data + 1, sym.size - 1, &v)) { + goto notfound; + } + } else { + /* Remove components from base until we find an entry or run out. */ + size_t baselen = base ? strlen(base) : 0; + char* tmp = malloc(sym.size + baselen + 1); + while (1) { + char* p = tmp; + if (baselen) { + memcpy(p, base, baselen); + p[baselen] = '.'; + p += baselen + 1; + } + memcpy(p, sym.data, sym.size); + p += sym.size; + if (_upb_DefPool_LookupSym(ctx->symtab, tmp, p - tmp, &v)) { + break; + } + if (!remove_component(tmp, &baselen)) { + free(tmp); + goto notfound; + } + } + free(tmp); + } -static const upb_MiniTable_Field google_protobuf_MessageOptions__fields[5] = { - {1, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(2, 2), 2, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(3, 3), 3, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {7, UPB_SIZE(4, 4), 4, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {999, UPB_SIZE(8, 8), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; + *type = _upb_DefType_Type(v); + return _upb_DefType_Unpack(v, *type); -const upb_MiniTable google_protobuf_MessageOptions_msginit = { - &google_protobuf_MessageOptions_submsgs[0], - &google_protobuf_MessageOptions__fields[0], - UPB_SIZE(16, 16), 5, kUpb_ExtMode_Extendable, 3, 255, 0, -}; +notfound: + _upb_DefBuilder_Errf(ctx, "couldn't resolve name '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(sym)); +} -static const upb_MiniTable_Sub google_protobuf_FieldOptions_submsgs[3] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, - {.subenum = &google_protobuf_FieldOptions_CType_enuminit}, - {.subenum = &google_protobuf_FieldOptions_JSType_enuminit}, -}; +const void* _upb_DefBuilder_Resolve(upb_DefBuilder* ctx, + const char* from_name_dbg, const char* base, + upb_StringView sym, upb_deftype_t type) { + upb_deftype_t found_type; + const void* ret = + _upb_DefBuilder_ResolveAny(ctx, from_name_dbg, base, sym, &found_type); + if (ret && found_type != type) { + _upb_DefBuilder_Errf(ctx, + "type mismatch when resolving %s: couldn't find " + "name " UPB_STRINGVIEW_FORMAT " with type=%d", + from_name_dbg, UPB_STRINGVIEW_ARGS(sym), (int)type); + } + return ret; +} -static const upb_MiniTable_Field google_protobuf_FieldOptions__fields[8] = { - {1, UPB_SIZE(4, 4), 1, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 12), 2, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(13, 13), 3, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(14, 14), 4, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(8, 8), 5, 2, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {10, UPB_SIZE(15, 15), 6, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {15, UPB_SIZE(16, 16), 7, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {999, UPB_SIZE(20, 24), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; +// Per ASCII this will lower-case a letter. If the result is a letter, the +// input was definitely a letter. If the output is not a letter, this may +// have transformed the character unpredictably. +static char upb_ascii_lower(char ch) { return ch | 0x20; } -const upb_MiniTable google_protobuf_FieldOptions_msginit = { - &google_protobuf_FieldOptions_submsgs[0], - &google_protobuf_FieldOptions__fields[0], - UPB_SIZE(24, 32), 8, kUpb_ExtMode_Extendable, 3, 255, 0, -}; +// isalpha() etc. from are locale-dependent, which we don't want. +static bool upb_isbetween(uint8_t c, uint8_t low, uint8_t high) { + return low <= c && c <= high; +} + +static bool upb_isletter(char c) { + char lower = upb_ascii_lower(c); + return upb_isbetween(lower, 'a', 'z') || c == '_'; +} + +static bool upb_isalphanum(char c) { + return upb_isletter(c) || upb_isbetween(c, '0', '9'); +} + +static bool TryGetChar(const char** src, const char* end, char* ch) { + if (*src == end) return false; + *ch = **src; + *src += 1; + return true; +} -static const upb_MiniTable_Sub google_protobuf_OneofOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; +static char TryGetHexDigit(const char** src, const char* end) { + char ch; + if (!TryGetChar(src, end, &ch)) return -1; + if ('0' <= ch && ch <= '9') { + return ch - '0'; + } + ch = upb_ascii_lower(ch); + if ('a' <= ch && ch <= 'f') { + return ch - 'a' + 0xa; + } + *src -= 1; // Char wasn't actually a hex digit. + return -1; +} -static const upb_MiniTable_Field google_protobuf_OneofOptions__fields[1] = { - {999, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; +static char upb_DefBuilder_ParseHexEscape(upb_DefBuilder* ctx, + const upb_FieldDef* f, + const char** src, const char* end) { + char hex_digit = TryGetHexDigit(src, end); + if (hex_digit < 0) { + _upb_DefBuilder_Errf( + ctx, "\\x cannot be followed by non-hex digit in field '%s' default", + upb_FieldDef_FullName(f)); + return 0; + } + unsigned int ret = hex_digit; + while ((hex_digit = TryGetHexDigit(src, end)) >= 0) { + ret = (ret << 4) | hex_digit; + } + if (ret > 0xff) { + _upb_DefBuilder_Errf(ctx, "Value of hex escape in field %s exceeds 8 bits", + upb_FieldDef_FullName(f)); + return 0; + } + return ret; +} -const upb_MiniTable google_protobuf_OneofOptions_msginit = { - &google_protobuf_OneofOptions_submsgs[0], - &google_protobuf_OneofOptions__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_Extendable, 0, 255, 0, -}; +static char TryGetOctalDigit(const char** src, const char* end) { + char ch; + if (!TryGetChar(src, end, &ch)) return -1; + if ('0' <= ch && ch <= '7') { + return ch - '0'; + } + *src -= 1; // Char wasn't actually an octal digit. + return -1; +} -static const upb_MiniTable_Sub google_protobuf_EnumOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; +static char upb_DefBuilder_ParseOctalEscape(upb_DefBuilder* ctx, + const upb_FieldDef* f, + const char** src, const char* end) { + char ch = 0; + for (int i = 0; i < 3; i++) { + char digit; + if ((digit = TryGetOctalDigit(src, end)) >= 0) { + ch = (ch << 3) | digit; + } + } + return ch; +} -static const upb_MiniTable_Field google_protobuf_EnumOptions__fields[3] = { - {2, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(2, 2), 2, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; +char _upb_DefBuilder_ParseEscape(upb_DefBuilder* ctx, const upb_FieldDef* f, + const char** src, const char* end) { + char ch; + if (!TryGetChar(src, end, &ch)) { + _upb_DefBuilder_Errf(ctx, "unterminated escape sequence in field %s", + upb_FieldDef_FullName(f)); + return 0; + } + switch (ch) { + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case '\\': + return '\\'; + case '\'': + return '\''; + case '\"': + return '\"'; + case '?': + return '\?'; + case 'x': + case 'X': + return upb_DefBuilder_ParseHexEscape(ctx, f, src, end); + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + *src -= 1; + return upb_DefBuilder_ParseOctalEscape(ctx, f, src, end); + } + _upb_DefBuilder_Errf(ctx, "Unknown escape sequence: \\%c", ch); +} -const upb_MiniTable google_protobuf_EnumOptions_msginit = { - &google_protobuf_EnumOptions_submsgs[0], - &google_protobuf_EnumOptions__fields[0], - UPB_SIZE(8, 16), 3, kUpb_ExtMode_Extendable, 0, 255, 0, -}; +void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name, + bool full) { + const char* str = name.data; + const size_t len = name.size; + bool start = true; + for (size_t i = 0; i < len; i++) { + const char c = str[i]; + if (c == '.') { + if (start || !full) { + _upb_DefBuilder_Errf( + ctx, "invalid name: unexpected '.' (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } + start = true; + } else if (start) { + if (!upb_isletter(c)) { + _upb_DefBuilder_Errf(ctx, + "invalid name: path components must start with a " + "letter (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } + start = false; + } else if (!upb_isalphanum(c)) { + _upb_DefBuilder_Errf( + ctx, + "invalid name: non-alphanumeric character (" UPB_STRINGVIEW_FORMAT + ")", + UPB_STRINGVIEW_ARGS(name)); + } + } + if (start) { + _upb_DefBuilder_Errf(ctx, + "invalid name: empty part (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } -static const upb_MiniTable_Sub google_protobuf_EnumValueOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; + // We should never reach this point. + UPB_ASSERT(false); +} -static const upb_MiniTable_Field google_protobuf_EnumValueOptions__fields[2] = { - {1, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; -const upb_MiniTable google_protobuf_EnumValueOptions_msginit = { - &google_protobuf_EnumValueOptions_submsgs[0], - &google_protobuf_EnumValueOptions__fields[0], - UPB_SIZE(8, 16), 2, kUpb_ExtMode_Extendable, 1, 255, 0, -}; -static const upb_MiniTable_Sub google_protobuf_ServiceOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; +// Must be last. -static const upb_MiniTable_Field google_protobuf_ServiceOptions__fields[2] = { - {33, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +struct upb_DefPool { + upb_Arena* arena; + upb_strtable syms; // full_name -> packed def ptr + upb_strtable files; // file_name -> (upb_FileDef*) + upb_inttable exts; // (upb_MiniTable_Extension*) -> (upb_FieldDef*) + upb_ExtensionRegistry* extreg; + void* scratch_data; + size_t scratch_size; + size_t bytes_loaded; }; -const upb_MiniTable google_protobuf_ServiceOptions_msginit = { - &google_protobuf_ServiceOptions_submsgs[0], - &google_protobuf_ServiceOptions__fields[0], - UPB_SIZE(8, 16), 2, kUpb_ExtMode_Extendable, 0, 255, 0, -}; +void upb_DefPool_Free(upb_DefPool* s) { + upb_Arena_Free(s->arena); + upb_gfree(s->scratch_data); + upb_gfree(s); +} -static const upb_MiniTable_Sub google_protobuf_MethodOptions_submsgs[2] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, - {.subenum = &google_protobuf_MethodOptions_IdempotencyLevel_enuminit}, -}; +upb_DefPool* upb_DefPool_New(void) { + upb_DefPool* s = upb_gmalloc(sizeof(*s)); + if (!s) return NULL; -static const upb_MiniTable_Field google_protobuf_MethodOptions__fields[3] = { - {33, UPB_SIZE(8, 8), 1, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {34, UPB_SIZE(4, 4), 2, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {999, UPB_SIZE(12, 16), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; + s->arena = upb_Arena_New(); + s->bytes_loaded = 0; -const upb_MiniTable google_protobuf_MethodOptions_msginit = { - &google_protobuf_MethodOptions_submsgs[0], - &google_protobuf_MethodOptions__fields[0], - UPB_SIZE(16, 24), 3, kUpb_ExtMode_Extendable, 0, 255, 0, -}; + s->scratch_size = 240; + s->scratch_data = upb_gmalloc(s->scratch_size); + if (!s->scratch_data) goto err; -static const upb_MiniTable_Sub google_protobuf_UninterpretedOption_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_NamePart_msginit}, -}; + if (!upb_strtable_init(&s->syms, 32, s->arena)) goto err; + if (!upb_strtable_init(&s->files, 4, s->arena)) goto err; + if (!upb_inttable_init(&s->exts, s->arena)) goto err; -static const upb_MiniTable_Field google_protobuf_UninterpretedOption__fields[7] = { - {2, UPB_SIZE(56, 80), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(32, 32), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(8, 8), 2, 0, 4, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(16, 16), 3, 0, 3, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(24, 24), 4, 0, 1, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, - {7, UPB_SIZE(40, 48), 5, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(48, 64), 6, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, -}; + s->extreg = upb_ExtensionRegistry_New(s->arena); + if (!s->extreg) goto err; -const upb_MiniTable google_protobuf_UninterpretedOption_msginit = { - &google_protobuf_UninterpretedOption_submsgs[0], - &google_protobuf_UninterpretedOption__fields[0], - UPB_SIZE(64, 96), 7, kUpb_ExtMode_NonExtendable, 0, 255, 0, -}; + return s; -static const upb_MiniTable_Field google_protobuf_UninterpretedOption_NamePart__fields[2] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(1, 1), 2, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, -}; +err: + upb_DefPool_Free(s); + return NULL; +} -const upb_MiniTable google_protobuf_UninterpretedOption_NamePart_msginit = { - NULL, - &google_protobuf_UninterpretedOption_NamePart__fields[0], - UPB_SIZE(16, 32), 2, kUpb_ExtMode_NonExtendable, 2, 255, 2, -}; +bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTable_Extension* ext, + upb_FieldDef* f) { + return upb_inttable_insert(&s->exts, (uintptr_t)ext, upb_value_constptr(f), + s->arena); +} -static const upb_MiniTable_Sub google_protobuf_SourceCodeInfo_submsgs[1] = { - {.submsg = &google_protobuf_SourceCodeInfo_Location_msginit}, -}; +bool _upb_DefPool_InsertSym(upb_DefPool* s, upb_StringView sym, upb_value v, + upb_Status* status) { + // TODO: table should support an operation "tryinsert" to avoid the double + // lookup. + if (upb_strtable_lookup2(&s->syms, sym.data, sym.size, NULL)) { + upb_Status_SetErrorFormat(status, "duplicate symbol '%s'", sym.data); + return false; + } + if (!upb_strtable_insert(&s->syms, sym.data, sym.size, v, s->arena)) { + upb_Status_SetErrorMessage(status, "out of memory"); + return false; + } + return true; +} -static const upb_MiniTable_Field google_protobuf_SourceCodeInfo__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; +static const void* _upb_DefPool_Unpack(const upb_DefPool* s, const char* sym, + size_t size, upb_deftype_t type) { + upb_value v; + return upb_strtable_lookup2(&s->syms, sym, size, &v) + ? _upb_DefType_Unpack(v, type) + : NULL; +} -const upb_MiniTable google_protobuf_SourceCodeInfo_msginit = { - &google_protobuf_SourceCodeInfo_submsgs[0], - &google_protobuf_SourceCodeInfo__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, -}; +bool _upb_DefPool_LookupSym(const upb_DefPool* s, const char* sym, size_t size, + upb_value* v) { + return upb_strtable_lookup2(&s->syms, sym, size, v); +} -static const upb_MiniTable_Field google_protobuf_SourceCodeInfo_Location__fields[5] = { - {1, UPB_SIZE(20, 40), 0, 0, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(24, 48), 0, 0, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(28, 56), 0, 0, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; +upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s) { + return s->extreg; +} -const upb_MiniTable google_protobuf_SourceCodeInfo_Location_msginit = { - NULL, - &google_protobuf_SourceCodeInfo_Location__fields[0], - UPB_SIZE(32, 64), 5, kUpb_ExtMode_NonExtendable, 4, 255, 0, -}; +void** _upb_DefPool_ScratchData(const upb_DefPool* s) { + return (void**)&s->scratch_data; +} -static const upb_MiniTable_Sub google_protobuf_GeneratedCodeInfo_submsgs[1] = { - {.submsg = &google_protobuf_GeneratedCodeInfo_Annotation_msginit}, -}; +size_t* _upb_DefPool_ScratchSize(const upb_DefPool* s) { + return (size_t*)&s->scratch_size; +} -static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; +const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, + const char* sym) { + return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_MSG); +} -const upb_MiniTable google_protobuf_GeneratedCodeInfo_msginit = { - &google_protobuf_GeneratedCodeInfo_submsgs[0], - &google_protobuf_GeneratedCodeInfo__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, -}; +const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( + const upb_DefPool* s, const char* sym, size_t len) { + return _upb_DefPool_Unpack(s, sym, len, UPB_DEFTYPE_MSG); +} -static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo_Annotation__fields[4] = { - {1, UPB_SIZE(20, 32), 0, 0, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 16), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(4, 4), 2, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(8, 8), 3, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, -}; +const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, + const char* sym) { + return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_ENUM); +} -const upb_MiniTable google_protobuf_GeneratedCodeInfo_Annotation_msginit = { - NULL, - &google_protobuf_GeneratedCodeInfo_Annotation__fields[0], - UPB_SIZE(24, 48), 4, kUpb_ExtMode_NonExtendable, 4, 255, 0, -}; +const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, + const char* sym) { + return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_ENUMVAL); +} -static const upb_MiniTable *messages_layout[27] = { - &google_protobuf_FileDescriptorSet_msginit, - &google_protobuf_FileDescriptorProto_msginit, - &google_protobuf_DescriptorProto_msginit, - &google_protobuf_DescriptorProto_ExtensionRange_msginit, - &google_protobuf_DescriptorProto_ReservedRange_msginit, - &google_protobuf_ExtensionRangeOptions_msginit, - &google_protobuf_FieldDescriptorProto_msginit, - &google_protobuf_OneofDescriptorProto_msginit, - &google_protobuf_EnumDescriptorProto_msginit, - &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, - &google_protobuf_EnumValueDescriptorProto_msginit, - &google_protobuf_ServiceDescriptorProto_msginit, - &google_protobuf_MethodDescriptorProto_msginit, - &google_protobuf_FileOptions_msginit, - &google_protobuf_MessageOptions_msginit, - &google_protobuf_FieldOptions_msginit, - &google_protobuf_OneofOptions_msginit, - &google_protobuf_EnumOptions_msginit, - &google_protobuf_EnumValueOptions_msginit, - &google_protobuf_ServiceOptions_msginit, - &google_protobuf_MethodOptions_msginit, - &google_protobuf_UninterpretedOption_msginit, - &google_protobuf_UninterpretedOption_NamePart_msginit, - &google_protobuf_SourceCodeInfo_msginit, - &google_protobuf_SourceCodeInfo_Location_msginit, - &google_protobuf_GeneratedCodeInfo_msginit, - &google_protobuf_GeneratedCodeInfo_Annotation_msginit, -}; +const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, + const char* name) { + upb_value v; + return upb_strtable_lookup(&s->files, name, &v) ? upb_value_getconstptr(v) + : NULL; +} -const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enuminit = { - NULL, - 0x7fffeULL, - 0, -}; +const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, + const char* name, + size_t len) { + upb_value v; + return upb_strtable_lookup2(&s->files, name, len, &v) + ? upb_value_getconstptr(v) + : NULL; +} -const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enuminit = { - NULL, - 0xeULL, - 0, -}; +const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( + const upb_DefPool* s, const char* name, size_t size) { + upb_value v; + if (!upb_strtable_lookup2(&s->syms, name, size, &v)) return NULL; -const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enuminit = { - NULL, - 0xeULL, - 0, -}; + switch (_upb_DefType_Type(v)) { + case UPB_DEFTYPE_FIELD: + return _upb_DefType_Unpack(v, UPB_DEFTYPE_FIELD); + case UPB_DEFTYPE_MSG: { + const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); + return _upb_MessageDef_InMessageSet(m) + ? upb_MessageDef_NestedExtension(m, 0) + : NULL; + } + default: + break; + } + + return NULL; +} -const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enuminit = { - NULL, - 0x7ULL, - 0, -}; +const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, + const char* sym) { + return upb_DefPool_FindExtensionByNameWithSize(s, sym, strlen(sym)); +} -const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enuminit = { - NULL, - 0x7ULL, - 0, -}; +const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, + const char* name) { + return _upb_DefPool_Unpack(s, name, strlen(name), UPB_DEFTYPE_SERVICE); +} -const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enuminit = { - NULL, - 0x7ULL, - 0, -}; +const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( + const upb_DefPool* s, const char* name, size_t size) { + return _upb_DefPool_Unpack(s, name, size, UPB_DEFTYPE_SERVICE); +} -static const upb_MiniTable_Enum *enums_layout[6] = { - &google_protobuf_FieldDescriptorProto_Type_enuminit, - &google_protobuf_FieldDescriptorProto_Label_enuminit, - &google_protobuf_FileOptions_OptimizeMode_enuminit, - &google_protobuf_FieldOptions_CType_enuminit, - &google_protobuf_FieldOptions_JSType_enuminit, - &google_protobuf_MethodOptions_IdempotencyLevel_enuminit, -}; +const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, + const char* name) { + upb_value v; + // TODO(haberman): non-extension fields and oneofs. + if (upb_strtable_lookup(&s->syms, name, &v)) { + switch (_upb_DefType_Type(v)) { + case UPB_DEFTYPE_EXT: { + const upb_FieldDef* f = _upb_DefType_Unpack(v, UPB_DEFTYPE_EXT); + return upb_FieldDef_File(f); + } + case UPB_DEFTYPE_MSG: { + const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); + return upb_MessageDef_File(m); + } + case UPB_DEFTYPE_ENUM: { + const upb_EnumDef* e = _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUM); + return upb_EnumDef_File(e); + } + case UPB_DEFTYPE_ENUMVAL: { + const upb_EnumValueDef* ev = + _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUMVAL); + return upb_EnumDef_File(upb_EnumValueDef_Enum(ev)); + } + case UPB_DEFTYPE_SERVICE: { + const upb_ServiceDef* service = + _upb_DefType_Unpack(v, UPB_DEFTYPE_SERVICE); + return upb_ServiceDef_File(service); + } + default: + UPB_UNREACHABLE(); + } + } -const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout = { - messages_layout, - enums_layout, - NULL, - 27, - 6, - 0, -}; + const char* last_dot = strrchr(name, '.'); + if (last_dot) { + const upb_MessageDef* parent = + upb_DefPool_FindMessageByNameWithSize(s, name, last_dot - name); + if (parent) { + const char* shortname = last_dot + 1; + if (upb_MessageDef_FindByNameWithSize(parent, shortname, + strlen(shortname), NULL, NULL)) { + return upb_MessageDef_File(parent); + } + } + } + return NULL; +} +static void remove_filedef(upb_DefPool* s, upb_FileDef* file) { + intptr_t iter = UPB_INTTABLE_BEGIN; + upb_StringView key; + upb_value val; + while (upb_strtable_next2(&s->syms, &key, &val, &iter)) { + const upb_FileDef* f; + switch (_upb_DefType_Type(val)) { + case UPB_DEFTYPE_EXT: + f = upb_FieldDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_EXT)); + break; + case UPB_DEFTYPE_MSG: + f = upb_MessageDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_MSG)); + break; + case UPB_DEFTYPE_ENUM: + f = upb_EnumDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_ENUM)); + break; + case UPB_DEFTYPE_ENUMVAL: + f = upb_EnumDef_File(upb_EnumValueDef_Enum( + _upb_DefType_Unpack(val, UPB_DEFTYPE_ENUMVAL))); + break; + case UPB_DEFTYPE_SERVICE: + f = upb_ServiceDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_SERVICE)); + break; + default: + UPB_UNREACHABLE(); + } -/** upb/def.c ************************************************************/ + if (f == file) upb_strtable_removeiter(&s->syms, &iter); + } +} -#include -#include -#include -#include -#include +static const upb_FileDef* _upb_DefPool_AddFile( + upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, + const upb_MiniTable_File* layout, upb_Status* status) { + const upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto); + if (name.size == 0) { + upb_Status_SetErrorFormat(status, + "missing name in google_protobuf_FileDescriptorProto"); + return NULL; + } -/* Must be last. */ + // Determine whether we already know about this file. + { + upb_value v; + if (upb_strtable_lookup2(&s->files, name.data, name.size, &v)) { + upb_Status_SetErrorFormat(status, + "duplicate file name " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(name)); + return NULL; + } + } -typedef struct { - size_t len; - char str[1]; /* Null-terminated string data follows. */ -} str_t; + upb_DefBuilder ctx = { + .symtab = s, + .layout = layout, + .msg_count = 0, + .enum_count = 0, + .ext_count = 0, + .status = status, + .file = NULL, + .arena = upb_Arena_New(), + .tmp_arena = upb_Arena_New(), + }; -/* The upb core does not generally have a concept of default instances. However - * for descriptor options we make an exception since the max size is known and - * modest (<200 bytes). All types can share a default instance since it is - * initialized to zeroes. - * - * We have to allocate an extra pointer for upb's internal metadata. */ -static const char opt_default_buf[_UPB_MAXOPT_SIZE + sizeof(void*)] = {0}; -static const char* opt_default = &opt_default_buf[sizeof(void*)]; + if (UPB_SETJMP(ctx.err)) { + UPB_ASSERT(!upb_Status_IsOk(status)); + if (ctx.file) { + remove_filedef(s, ctx.file); + ctx.file = NULL; + } + } else if (!ctx.arena || !ctx.tmp_arena) { + _upb_DefBuilder_OomErr(&ctx); + } else { + _upb_FileDef_Create(&ctx, file_proto); + upb_strtable_insert(&s->files, name.data, name.size, + upb_value_constptr(ctx.file), ctx.arena); + UPB_ASSERT(upb_Status_IsOk(status)); + upb_Arena_Fuse(s->arena, ctx.arena); + } -struct upb_FieldDef { - const google_protobuf_FieldOptions* opts; - const upb_FileDef* file; - const upb_MessageDef* msgdef; - const char* full_name; - const char* json_name; - union { - int64_t sint; - uint64_t uint; - double dbl; - float flt; - bool boolean; - str_t* str; - } defaultval; - union { - const upb_OneofDef* oneof; - const upb_MessageDef* extension_scope; - } scope; - union { - const upb_MessageDef* msgdef; - const upb_EnumDef* enumdef; - const google_protobuf_FieldDescriptorProto* unresolved; - } sub; - uint32_t number_; - uint16_t index_; - uint16_t layout_index; /* Index into msgdef->layout->fields or file->exts */ - bool has_default; - bool is_extension_; - bool packed_; - bool proto3_optional_; - bool has_json_name_; - upb_FieldType type_; - upb_Label label_; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif -}; + if (ctx.arena) upb_Arena_Free(ctx.arena); + if (ctx.tmp_arena) upb_Arena_Free(ctx.tmp_arena); + return ctx.file; +} -struct upb_ExtensionRange { - const google_protobuf_ExtensionRangeOptions* opts; - int32_t start; - int32_t end; -}; +const upb_FileDef* upb_DefPool_AddFile( + upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, + upb_Status* status) { + return _upb_DefPool_AddFile(s, file_proto, NULL, status); +} -struct upb_MessageDef { - const google_protobuf_MessageOptions* opts; - const upb_MiniTable* layout; - const upb_FileDef* file; - const upb_MessageDef* containing_type; - const char* full_name; +/* Include here since we want most of this file to be stdio-free. */ +#include - /* Tables for looking up fields by number and name. */ - upb_inttable itof; - upb_strtable ntof; +bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, + bool rebuild_minitable) { + /* Since this function should never fail (it would indicate a bug in upb) we + * print errors to stderr instead of returning error status to the user. */ + _upb_DefPool_Init** deps = init->deps; + google_protobuf_FileDescriptorProto* file; + upb_Arena* arena; + upb_Status status; - /* All nested defs. - * MEM: We could save some space here by putting nested defs in a contiguous - * region and calculating counts from offsets or vice-versa. */ - const upb_FieldDef* fields; - const upb_OneofDef* oneofs; - const upb_ExtensionRange* ext_ranges; - const upb_MessageDef* nested_msgs; - const upb_EnumDef* nested_enums; - const upb_FieldDef* nested_exts; - int field_count; - int real_oneof_count; - int oneof_count; - int ext_range_count; - int nested_msg_count; - int nested_enum_count; - int nested_ext_count; - bool in_message_set; - upb_WellKnown well_known_type; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif -}; + upb_Status_Clear(&status); -struct upb_EnumDef { - const google_protobuf_EnumOptions* opts; - const upb_MiniTable_Enum* layout; // Only for proto2. - const upb_FileDef* file; - const upb_MessageDef* containing_type; // Could be merged with "file". - const char* full_name; - upb_strtable ntoi; - upb_inttable iton; - const upb_EnumValueDef* values; - int value_count; - int32_t defaultval; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif -}; + if (upb_DefPool_FindFileByName(s, init->filename)) { + return true; + } -struct upb_EnumValueDef { - const google_protobuf_EnumValueOptions* opts; - const upb_EnumDef* parent; - const char* full_name; - int32_t number; -}; + arena = upb_Arena_New(); -struct upb_OneofDef { - const google_protobuf_OneofOptions* opts; - const upb_MessageDef* parent; - const char* full_name; - int field_count; - bool synthetic; - const upb_FieldDef** fields; - upb_strtable ntof; - upb_inttable itof; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif -}; + for (; *deps; deps++) { + if (!_upb_DefPool_LoadDefInitEx(s, *deps, rebuild_minitable)) goto err; + } -struct upb_FileDef { - const google_protobuf_FileOptions* opts; - const char* name; - const char* package; + file = google_protobuf_FileDescriptorProto_parse_ex( + init->descriptor.data, init->descriptor.size, NULL, + kUpb_DecodeOption_AliasString, arena); + s->bytes_loaded += init->descriptor.size; - const upb_FileDef** deps; - const int32_t* public_deps; - const int32_t* weak_deps; - const upb_MessageDef* top_lvl_msgs; - const upb_EnumDef* top_lvl_enums; - const upb_FieldDef* top_lvl_exts; - const upb_ServiceDef* services; - const upb_MiniTable_Extension** ext_layouts; - const upb_DefPool* symtab; + if (!file) { + upb_Status_SetErrorFormat( + &status, + "Failed to parse compiled-in descriptor for file '%s'. This should " + "never happen.", + init->filename); + goto err; + } - int dep_count; - int public_dep_count; - int weak_dep_count; - int top_lvl_msg_count; - int top_lvl_enum_count; - int top_lvl_ext_count; - int service_count; - int ext_count; /* All exts in the file. */ - upb_Syntax syntax; -}; + const upb_MiniTable_File* mt = rebuild_minitable ? NULL : init->layout; + if (!_upb_DefPool_AddFile(s, file, mt, &status)) { + goto err; + } -struct upb_MethodDef { - const google_protobuf_MethodOptions* opts; - upb_ServiceDef* service; - const char* full_name; - const upb_MessageDef* input_type; - const upb_MessageDef* output_type; - int index; - bool client_streaming; - bool server_streaming; -}; + upb_Arena_Free(arena); + return true; -struct upb_ServiceDef { - const google_protobuf_ServiceOptions* opts; - const upb_FileDef* file; - const char* full_name; - upb_MethodDef* methods; - int method_count; - int index; -}; +err: + fprintf(stderr, + "Error loading compiled-in descriptor for file '%s' (this should " + "never happen): %s\n", + init->filename, upb_Status_ErrorMessage(&status)); + upb_Arena_Free(arena); + return false; +} -struct upb_DefPool { - upb_Arena* arena; - upb_strtable syms; /* full_name -> packed def ptr */ - upb_strtable files; /* file_name -> upb_FileDef* */ - upb_inttable exts; /* upb_MiniTable_Extension* -> upb_FieldDef* */ - upb_ExtensionRegistry* extreg; - size_t bytes_loaded; -}; +size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s) { + return s->bytes_loaded; +} -/* Inside a symtab we store tagged pointers to specific def types. */ -typedef enum { - UPB_DEFTYPE_MASK = 7, +upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s) { return s->arena; } - /* Only inside symtab table. */ - UPB_DEFTYPE_EXT = 0, - UPB_DEFTYPE_MSG = 1, - UPB_DEFTYPE_ENUM = 2, - UPB_DEFTYPE_ENUMVAL = 3, - UPB_DEFTYPE_SERVICE = 4, +const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable( + const upb_DefPool* s, const upb_MiniTable_Extension* ext) { + upb_value v; + bool ok = upb_inttable_lookup(&s->exts, (uintptr_t)ext, &v); + UPB_ASSERT(ok); + return upb_value_getconstptr(v); +} - /* Only inside message table. */ - UPB_DEFTYPE_FIELD = 0, - UPB_DEFTYPE_ONEOF = 1, - UPB_DEFTYPE_FIELD_JSONNAME = 2, +const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, + const upb_MessageDef* m, + int32_t fieldnum) { + const upb_MiniTable* l = upb_MessageDef_MiniTable(m); + const upb_MiniTable_Extension* ext = _upb_extreg_get(s->extreg, l, fieldnum); + return ext ? _upb_DefPool_FindExtensionByMiniTable(s, ext) : NULL; +} - /* Only inside file table. */ - UPB_DEFTYPE_FILE = 0, - UPB_DEFTYPE_LAYOUT = 1 -} upb_deftype_t; +const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( + const upb_DefPool* s) { + return s->extreg; +} -#define FIELD_TYPE_UNSPECIFIED 0 +const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, + const upb_MessageDef* m, + size_t* count) { + size_t n = 0; + intptr_t iter = UPB_INTTABLE_BEGIN; + uintptr_t key; + upb_value val; + // This is O(all exts) instead of O(exts for m). If we need this to be + // efficient we may need to make extreg into a two-level table, or have a + // second per-message index. + while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { + const upb_FieldDef* f = upb_value_getconstptr(val); + if (upb_FieldDef_ContainingType(f) == m) n++; + } + const upb_FieldDef** exts = malloc(n * sizeof(*exts)); + iter = UPB_INTTABLE_BEGIN; + size_t i = 0; + while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { + const upb_FieldDef* f = upb_value_getconstptr(val); + if (upb_FieldDef_ContainingType(f) == m) exts[i++] = f; + } + *count = n; + return exts; +} -static upb_deftype_t deftype(upb_value v) { - uintptr_t num = (uintptr_t)upb_value_getconstptr(v); - return num & UPB_DEFTYPE_MASK; +bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init) { + return _upb_DefPool_LoadDefInitEx(s, init, false); } -static const void* unpack_def(upb_value v, upb_deftype_t type) { - uintptr_t num = (uintptr_t)upb_value_getconstptr(v); - return (num & UPB_DEFTYPE_MASK) == type - ? (const void*)(num & ~UPB_DEFTYPE_MASK) - : NULL; + +// Must be last. + +upb_deftype_t _upb_DefType_Type(upb_value v) { + const uintptr_t num = (uintptr_t)upb_value_getconstptr(v); + return num & UPB_DEFTYPE_MASK; } -static upb_value pack_def(const void* ptr, upb_deftype_t type) { - // Our 3-bit pointer tagging requires all pointers to be multiples of 8. - // The arena will always yield 8-byte-aligned addresses, however we put - // the defs into arrays. For each element in the array to be 8-byte-aligned, - // the sizes of each def type must also be a multiple of 8. - // - // If any of these asserts fail, we need to add or remove padding on 32-bit - // machines (64-bit machines will have 8-byte alignment already due to - // pointers, which all of these structs have). - UPB_ASSERT((sizeof(upb_FieldDef) & UPB_DEFTYPE_MASK) == 0); - UPB_ASSERT((sizeof(upb_MessageDef) & UPB_DEFTYPE_MASK) == 0); - UPB_ASSERT((sizeof(upb_EnumDef) & UPB_DEFTYPE_MASK) == 0); - UPB_ASSERT((sizeof(upb_EnumValueDef) & UPB_DEFTYPE_MASK) == 0); - UPB_ASSERT((sizeof(upb_ServiceDef) & UPB_DEFTYPE_MASK) == 0); - UPB_ASSERT((sizeof(upb_OneofDef) & UPB_DEFTYPE_MASK) == 0); +upb_value _upb_DefType_Pack(const void* ptr, upb_deftype_t type) { uintptr_t num = (uintptr_t)ptr; UPB_ASSERT((num & UPB_DEFTYPE_MASK) == 0); num |= type; return upb_value_constptr((const void*)num); } -/* isalpha() etc. from are locale-dependent, which we don't want. */ -static bool upb_isbetween(uint8_t c, uint8_t low, uint8_t high) { - return c >= low && c <= high; +const void* _upb_DefType_Unpack(upb_value v, upb_deftype_t type) { + uintptr_t num = (uintptr_t)upb_value_getconstptr(v); + return (num & UPB_DEFTYPE_MASK) == type + ? (const void*)(num & ~UPB_DEFTYPE_MASK) + : NULL; } -static char upb_ascii_lower(char ch) { - // Per ASCII this will lower-case a letter. If the result is a letter, the - // input was definitely a letter. If the output is not a letter, this may - // have transformed the character unpredictably. - return ch | 0x20; -} -static bool upb_isletter(char c) { - char lower = upb_ascii_lower(c); - return upb_isbetween(lower, 'a', 'z') || c == '_'; -} +// Must be last. -static bool upb_isalphanum(char c) { - return upb_isletter(c) || upb_isbetween(c, '0', '9'); -} +bool _upb_DescState_Grow(upb_DescState* d, upb_Arena* a) { + const size_t oldbufsize = d->bufsize; + const int used = d->ptr - d->buf; -static const char* shortdefname(const char* fullname) { - const char* p; + if (!d->buf) { + d->buf = upb_Arena_Malloc(a, d->bufsize); + if (!d->buf) return false; + d->ptr = d->buf; + d->e.end = d->buf + d->bufsize; + } - if (fullname == NULL) { - return NULL; - } else if ((p = strrchr(fullname, '.')) == NULL) { - /* No '.' in the name, return the full string. */ - return fullname; - } else { - /* Return one past the last '.'. */ - return p + 1; + if (oldbufsize - used < kUpb_MtDataEncoder_MinSize) { + d->bufsize *= 2; + d->buf = upb_Arena_Realloc(a, d->buf, oldbufsize, d->bufsize); + if (!d->buf) return false; + d->ptr = d->buf + used; + d->e.end = d->buf + d->bufsize; } + + return true; } -/* All submessage fields are lower than all other fields. - * Secondly, fields are increasing in order. */ -uint32_t field_rank(const upb_FieldDef* f) { - uint32_t ret = upb_FieldDef_Number(f); - const uint32_t high_bit = 1 << 30; - UPB_ASSERT(ret < high_bit); - if (!upb_FieldDef_IsSubMessage(f)) ret |= high_bit; - return ret; + +#include + + +// Must be last. + +struct upb_EnumDef { + const google_protobuf_EnumOptions* opts; + const upb_MiniTable_Enum* layout; // Only for proto2. + const upb_FileDef* file; + const upb_MessageDef* containing_type; // Could be merged with "file". + const char* full_name; + upb_strtable ntoi; + upb_inttable iton; + const upb_EnumValueDef* values; + int value_count; + int32_t defaultval; + bool is_sorted; // Whether all of the values are defined in ascending order. +}; + +upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i) { + return (upb_EnumDef*)&e[i]; } -int cmp_fields(const void* p1, const void* p2) { - const upb_FieldDef* f1 = *(upb_FieldDef* const*)p1; - const upb_FieldDef* f2 = *(upb_FieldDef* const*)p2; - return field_rank(f1) - field_rank(f2); +// TODO: Maybe implement this on top of a ZCOS instead? +void _upb_EnumDef_Debug(const upb_EnumDef* e) { + fprintf(stderr, "enum %s (%p) {\n", e->full_name, e); + fprintf(stderr, " value_count: %d\n", e->value_count); + fprintf(stderr, " default: %d\n", e->defaultval); + fprintf(stderr, " is_sorted: %d\n", e->is_sorted); + fprintf(stderr, "}\n"); } -static void upb_Status_setoom(upb_Status* status) { - upb_Status_SetErrorMessage(status, "out of memory"); +const upb_MiniTable_Enum* _upb_EnumDef_MiniTable(const upb_EnumDef* e) { + return e->layout; } -static void assign_msg_wellknowntype(upb_MessageDef* m) { - const char* name = upb_MessageDef_FullName(m); - if (name == NULL) { - m->well_known_type = kUpb_WellKnown_Unspecified; - return; - } - if (!strcmp(name, "google.protobuf.Any")) { - m->well_known_type = kUpb_WellKnown_Any; - } else if (!strcmp(name, "google.protobuf.FieldMask")) { - m->well_known_type = kUpb_WellKnown_FieldMask; - } else if (!strcmp(name, "google.protobuf.Duration")) { - m->well_known_type = kUpb_WellKnown_Duration; - } else if (!strcmp(name, "google.protobuf.Timestamp")) { - m->well_known_type = kUpb_WellKnown_Timestamp; - } else if (!strcmp(name, "google.protobuf.DoubleValue")) { - m->well_known_type = kUpb_WellKnown_DoubleValue; - } else if (!strcmp(name, "google.protobuf.FloatValue")) { - m->well_known_type = kUpb_WellKnown_FloatValue; - } else if (!strcmp(name, "google.protobuf.Int64Value")) { - m->well_known_type = kUpb_WellKnown_Int64Value; - } else if (!strcmp(name, "google.protobuf.UInt64Value")) { - m->well_known_type = kUpb_WellKnown_UInt64Value; - } else if (!strcmp(name, "google.protobuf.Int32Value")) { - m->well_known_type = kUpb_WellKnown_Int32Value; - } else if (!strcmp(name, "google.protobuf.UInt32Value")) { - m->well_known_type = kUpb_WellKnown_UInt32Value; - } else if (!strcmp(name, "google.protobuf.BoolValue")) { - m->well_known_type = kUpb_WellKnown_BoolValue; - } else if (!strcmp(name, "google.protobuf.StringValue")) { - m->well_known_type = kUpb_WellKnown_StringValue; - } else if (!strcmp(name, "google.protobuf.BytesValue")) { - m->well_known_type = kUpb_WellKnown_BytesValue; - } else if (!strcmp(name, "google.protobuf.Value")) { - m->well_known_type = kUpb_WellKnown_Value; - } else if (!strcmp(name, "google.protobuf.ListValue")) { - m->well_known_type = kUpb_WellKnown_ListValue; - } else if (!strcmp(name, "google.protobuf.Struct")) { - m->well_known_type = kUpb_WellKnown_Struct; - } else { - m->well_known_type = kUpb_WellKnown_Unspecified; +bool _upb_EnumDef_Insert(upb_EnumDef* e, upb_EnumValueDef* v, upb_Arena* a) { + const char* name = upb_EnumValueDef_Name(v); + const upb_value val = upb_value_constptr(v); + bool ok = upb_strtable_insert(&e->ntoi, name, strlen(name), val, a); + if (!ok) return false; + + // Multiple enumerators can have the same number, first one wins. + const int number = upb_EnumValueDef_Number(v); + if (!upb_inttable_lookup(&e->iton, number, NULL)) { + return upb_inttable_insert(&e->iton, number, val, a); } + return true; } -/* upb_EnumDef ****************************************************************/ - const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e) { return e->opts; } bool upb_EnumDef_HasOptions(const upb_EnumDef* e) { - return e->opts != (void*)opt_default; + return e->opts != (void*)kUpbDefOptDefault; } const char* upb_EnumDef_FullName(const upb_EnumDef* e) { return e->full_name; } const char* upb_EnumDef_Name(const upb_EnumDef* e) { - return shortdefname(e->full_name); + return _upb_DefBuilder_FullToShort(e->full_name); } const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e) { return e->file; } @@ -5546,19 +6370,24 @@ int32_t upb_EnumDef_Default(const upb_EnumDef* e) { int upb_EnumDef_ValueCount(const upb_EnumDef* e) { return e->value_count; } +const upb_EnumValueDef* upb_EnumDef_FindValueByName(const upb_EnumDef* e, + const char* name) { + return upb_EnumDef_FindValueByNameWithSize(e, name, strlen(name)); +} + const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( - const upb_EnumDef* def, const char* name, size_t len) { + const upb_EnumDef* e, const char* name, size_t size) { upb_value v; - return upb_strtable_lookup2(&def->ntoi, name, len, &v) + return upb_strtable_lookup2(&e->ntoi, name, size, &v) ? upb_value_getconstptr(v) : NULL; } -const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* def, +const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* e, int32_t num) { upb_value v; - return upb_inttable_lookup(&def->iton, num, &v) ? upb_value_getconstptr(v) - : NULL; + return upb_inttable_lookup(&e->iton, num, &v) ? upb_value_getconstptr(v) + : NULL; } bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num) { @@ -5569,2192 +6398,2325 @@ bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num) { const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i) { UPB_ASSERT(0 <= i && i < e->value_count); - return &e->values[i]; + return _upb_EnumValueDef_At(e->values, i); +} + +bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, + upb_StringView* out) { + upb_DescState s; + _upb_DescState_Init(&s); + + const upb_EnumValueDef** sorted = NULL; + if (!e->is_sorted) { + sorted = _upb_EnumValueDefs_Sorted(e->values, e->value_count, a); + if (!sorted) return false; + } + + upb_MtDataEncoder_StartEnum(&s.e); + + // Duplicate values are allowed but we only encode each value once. + uint32_t previous = 0; + + for (size_t i = 0; i < e->value_count; i++) { + const uint32_t current = + upb_EnumValueDef_Number(sorted ? sorted[i] : upb_EnumDef_Value(e, i)); + if (i != 0 && previous == current) continue; + + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_PutEnumValue(&s.e, s.ptr, current); + previous = current; + } + + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_EndEnum(&s.e, s.ptr); + + // There will always be room for this '\0' in the encoder buffer because + // kUpb_MtDataEncoder_MinSize is overkill for upb_MtDataEncoder_EndEnum(). + UPB_ASSERT(s.ptr < s.buf + s.bufsize); + *s.ptr = '\0'; + + out->data = s.buf; + out->size = s.ptr - s.buf; + return true; +} + +static upb_MiniTable_Enum* create_enumlayout(upb_DefBuilder* ctx, + const upb_EnumDef* e) { + upb_StringView sv; + bool ok = upb_EnumDef_MiniDescriptorEncode(e, ctx->tmp_arena, &sv); + if (!ok) _upb_DefBuilder_Errf(ctx, "OOM while building enum MiniDescriptor"); + + upb_Status status; + upb_MiniTable_Enum* layout = + upb_MiniTable_BuildEnum(sv.data, sv.size, ctx->arena, &status); + if (!layout) + _upb_DefBuilder_Errf(ctx, "Error building enum MiniTable: %s", status.msg); + return layout; } -/* upb_EnumValueDef ***********************************************************/ +static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_EnumDescriptorProto* enum_proto, + upb_EnumDef* e) { + const google_protobuf_EnumValueDescriptorProto* const* values; + upb_StringView name; + size_t n; + + // Must happen before _upb_DefBuilder_Add() + e->file = _upb_DefBuilder_File(ctx); + + name = google_protobuf_EnumDescriptorProto_name(enum_proto); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); + + e->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + _upb_DefBuilder_Add(ctx, e->full_name, + _upb_DefType_Pack(e, UPB_DEFTYPE_ENUM)); + + values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n); + + bool ok = upb_strtable_init(&e->ntoi, n, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_inttable_init(&e->iton, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + e->defaultval = 0; + e->value_count = n; + e->values = _upb_EnumValueDefs_New(ctx, prefix, n, values, e, &e->is_sorted); + + if (n == 0) { + _upb_DefBuilder_Errf(ctx, "enums must contain at least one value (%s)", + e->full_name); + } + + UBP_DEF_SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); -const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( - const upb_EnumValueDef* e) { - return e->opts; -} + upb_inttable_compact(&e->iton, ctx->arena); -bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* e) { - return e->opts != (void*)opt_default; + if (upb_FileDef_Syntax(e->file) == kUpb_Syntax_Proto2) { + if (ctx->layout) { + UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count); + e->layout = ctx->layout->enums[ctx->enum_count++]; + } else { + e->layout = create_enumlayout(ctx, e); + } + } else { + e->layout = NULL; + } } -const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* ev) { - return ev->parent; -} +upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, + const google_protobuf_EnumDescriptorProto* const* protos, + const upb_MessageDef* containing_type) { + _upb_DefType_CheckPadding(sizeof(upb_EnumDef)); -const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* ev) { - return ev->full_name; -} + // If a containing type is defined then get the full name from that. + // Otherwise use the package name from the file def. + const char* name = containing_type ? upb_MessageDef_FullName(containing_type) + : _upb_FileDef_RawPackage(ctx->file); -const char* upb_EnumValueDef_Name(const upb_EnumValueDef* ev) { - return shortdefname(ev->full_name); + upb_EnumDef* e = _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumDef) * n); + for (size_t i = 0; i < n; i++) { + create_enumdef(ctx, name, protos[i], &e[i]); + e[i].containing_type = containing_type; + } + return e; } -int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* ev) { - return ev->number; -} -uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* ev) { - // Compute index in our parent's array. - return ev - ev->parent->values; -} -/* upb_ExtensionRange - * ***************************************************************/ +// Must be last. -const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( - const upb_ExtensionRange* r) { - return r->opts; -} +struct upb_EnumValueDef { + const google_protobuf_EnumValueOptions* opts; + const upb_EnumDef* parent; + const char* full_name; + int32_t number; +}; -bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r) { - return r->opts != (void*)opt_default; +upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i) { + return (upb_EnumValueDef*)&v[i]; } -int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* e) { - return e->start; +static int _upb_EnumValueDef_Compare(const void* p1, const void* p2) { + const uint32_t v1 = (*(const upb_EnumValueDef**)p1)->number; + const uint32_t v2 = (*(const upb_EnumValueDef**)p2)->number; + return (v1 < v2) ? -1 : (v1 > v2); } -int32_t upb_ExtensionRange_End(const upb_ExtensionRange* e) { return e->end; } +const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v, + int n, upb_Arena* a) { + // TODO: Try to replace this arena alloc with a persistent scratch buffer. + upb_EnumValueDef** out = + (upb_EnumValueDef**)upb_Arena_Malloc(a, n * sizeof(void*)); + if (!out) return NULL; -/* upb_FieldDef ***************************************************************/ + for (int i = 0; i < n; i++) { + out[i] = (upb_EnumValueDef*)&v[i]; + } + qsort(out, n, sizeof(void*), _upb_EnumValueDef_Compare); -const google_protobuf_FieldOptions* upb_FieldDef_Options( - const upb_FieldDef* f) { - return f->opts; + return (const upb_EnumValueDef**)out; } -bool upb_FieldDef_HasOptions(const upb_FieldDef* f) { - return f->opts != (void*)opt_default; +const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( + const upb_EnumValueDef* v) { + return v->opts; } -const char* upb_FieldDef_FullName(const upb_FieldDef* f) { - return f->full_name; +bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* v) { + return v->opts != (void*)kUpbDefOptDefault; } -upb_CType upb_FieldDef_CType(const upb_FieldDef* f) { - switch (f->type_) { - case kUpb_FieldType_Double: - return kUpb_CType_Double; - case kUpb_FieldType_Float: - return kUpb_CType_Float; - case kUpb_FieldType_Int64: - case kUpb_FieldType_SInt64: - case kUpb_FieldType_SFixed64: - return kUpb_CType_Int64; - case kUpb_FieldType_Int32: - case kUpb_FieldType_SFixed32: - case kUpb_FieldType_SInt32: - return kUpb_CType_Int32; - case kUpb_FieldType_UInt64: - case kUpb_FieldType_Fixed64: - return kUpb_CType_UInt64; - case kUpb_FieldType_UInt32: - case kUpb_FieldType_Fixed32: - return kUpb_CType_UInt32; - case kUpb_FieldType_Enum: - return kUpb_CType_Enum; - case kUpb_FieldType_Bool: - return kUpb_CType_Bool; - case kUpb_FieldType_String: - return kUpb_CType_String; - case kUpb_FieldType_Bytes: - return kUpb_CType_Bytes; - case kUpb_FieldType_Group: - case kUpb_FieldType_Message: - return kUpb_CType_Message; - } - UPB_UNREACHABLE(); +const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* v) { + return v->parent; } -upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f) { return f->type_; } - -uint32_t upb_FieldDef_Index(const upb_FieldDef* f) { return f->index_; } - -upb_Label upb_FieldDef_Label(const upb_FieldDef* f) { return f->label_; } - -uint32_t upb_FieldDef_Number(const upb_FieldDef* f) { return f->number_; } +const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* v) { + return v->full_name; +} -bool upb_FieldDef_IsExtension(const upb_FieldDef* f) { - return f->is_extension_; +const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v) { + return _upb_DefBuilder_FullToShort(v->full_name); } -bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { return f->packed_; } +int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v) { return v->number; } -const char* upb_FieldDef_Name(const upb_FieldDef* f) { - return shortdefname(f->full_name); +uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v) { + // Compute index in our parent's array. + return v - upb_EnumDef_Value(v->parent, 0); } -const char* upb_FieldDef_JsonName(const upb_FieldDef* f) { - return f->json_name; -} +static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_EnumValueDescriptorProto* val_proto, + upb_EnumDef* e, upb_EnumValueDef* v) { + upb_StringView name = google_protobuf_EnumValueDescriptorProto_name(val_proto); -bool upb_FieldDef_HasJsonName(const upb_FieldDef* f) { - return f->has_json_name_; -} + v->parent = e; // Must happen prior to _upb_DefBuilder_Add() + v->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + v->number = google_protobuf_EnumValueDescriptorProto_number(val_proto); + _upb_DefBuilder_Add(ctx, v->full_name, + _upb_DefType_Pack(v, UPB_DEFTYPE_ENUMVAL)); -const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f) { return f->file; } + UBP_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions, + val_proto); -const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f) { - return f->msgdef; + bool ok = _upb_EnumDef_Insert(e, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); } -const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f) { - return f->is_extension_ ? f->scope.extension_scope : NULL; -} +// Allocate and initialize an array of |n| enum value defs owned by |e|. +upb_EnumValueDef* _upb_EnumValueDefs_New( + upb_DefBuilder* ctx, const char* prefix, int n, + const google_protobuf_EnumValueDescriptorProto* const* protos, upb_EnumDef* e, + bool* is_sorted) { + _upb_DefType_CheckPadding(sizeof(upb_EnumValueDef)); -const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f) { - return f->is_extension_ ? NULL : f->scope.oneof; -} + upb_EnumValueDef* v = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumValueDef) * n); -const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f) { - const upb_OneofDef* oneof = upb_FieldDef_ContainingOneof(f); - if (!oneof || upb_OneofDef_IsSynthetic(oneof)) return NULL; - return oneof; -} + *is_sorted = true; + uint32_t previous = 0; + for (size_t i = 0; i < n; i++) { + create_enumvaldef(ctx, prefix, protos[i], e, &v[i]); -upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f) { - UPB_ASSERT(!upb_FieldDef_IsSubMessage(f)); - upb_MessageValue ret; + const uint32_t current = v[i].number; + if (previous > current) *is_sorted = false; + previous = current; + } - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Bool: - return (upb_MessageValue){.bool_val = f->defaultval.boolean}; - case kUpb_CType_Int64: - return (upb_MessageValue){.int64_val = f->defaultval.sint}; - case kUpb_CType_UInt64: - return (upb_MessageValue){.uint64_val = f->defaultval.uint}; - case kUpb_CType_Enum: - case kUpb_CType_Int32: - return (upb_MessageValue){.int32_val = (int32_t)f->defaultval.sint}; - case kUpb_CType_UInt32: - return (upb_MessageValue){.uint32_val = (uint32_t)f->defaultval.uint}; - case kUpb_CType_Float: - return (upb_MessageValue){.float_val = f->defaultval.flt}; - case kUpb_CType_Double: - return (upb_MessageValue){.double_val = f->defaultval.dbl}; - case kUpb_CType_String: - case kUpb_CType_Bytes: { - str_t* str = f->defaultval.str; - if (str) { - return (upb_MessageValue){ - .str_val = (upb_StringView){.data = str->str, .size = str->len}}; - } else { - return (upb_MessageValue){ - .str_val = (upb_StringView){.data = NULL, .size = 0}}; - } - } - default: - UPB_UNREACHABLE(); + if (upb_FileDef_Syntax(ctx->file) == kUpb_Syntax_Proto3 && n > 0 && + v[0].number != 0) { + _upb_DefBuilder_Errf(ctx, + "for proto3, the first enum value must be zero (%s)", + upb_EnumDef_FullName(e)); } - return ret; + return v; } -const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Message ? f->sub.msgdef : NULL; -} -const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Enum ? f->sub.enumdef : NULL; -} -const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f) { - UPB_ASSERT(!upb_FieldDef_IsExtension(f)); - return &f->msgdef->layout->fields[f->layout_index]; -} +// Must be last. -const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable( - const upb_FieldDef* f) { - UPB_ASSERT(upb_FieldDef_IsExtension(f)); - return f->file->ext_layouts[f->layout_index]; -} +struct upb_ExtensionRange { + const google_protobuf_ExtensionRangeOptions* opts; + int32_t start; + int32_t end; +}; -bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) { - return f->proto3_optional_; +upb_ExtensionRange* _upb_ExtensionRange_At(const upb_ExtensionRange* r, int i) { + return (upb_ExtensionRange*)&r[i]; } -bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Message; +const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( + const upb_ExtensionRange* r) { + return r->opts; } -bool upb_FieldDef_IsString(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_String || - upb_FieldDef_CType(f) == kUpb_CType_Bytes; +bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r) { + return r->opts != (void*)kUpbDefOptDefault; } -bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) { - return upb_FieldDef_Label(f) == kUpb_Label_Repeated; +int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* r) { + return r->start; } -bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f) { - return !upb_FieldDef_IsString(f) && !upb_FieldDef_IsSubMessage(f); -} +int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r) { return r->end; } -bool upb_FieldDef_IsMap(const upb_FieldDef* f) { - return upb_FieldDef_IsRepeated(f) && upb_FieldDef_IsSubMessage(f) && - upb_MessageDef_IsMapEntry(upb_FieldDef_MessageSubDef(f)); -} +upb_ExtensionRange* _upb_ExtensionRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_DescriptorProto_ExtensionRange* const* protos, + const upb_MessageDef* m) { + upb_ExtensionRange* r = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_ExtensionRange) * n); -bool upb_FieldDef_HasDefault(const upb_FieldDef* f) { return f->has_default; } + for (int i = 0; i < n; i++) { + const int32_t start = + google_protobuf_DescriptorProto_ExtensionRange_start(protos[i]); + const int32_t end = google_protobuf_DescriptorProto_ExtensionRange_end(protos[i]); + const int32_t max = + google_protobuf_MessageOptions_message_set_wire_format(upb_MessageDef_Options(m)) + ? INT32_MAX + : kUpb_MaxFieldNumber + 1; -bool upb_FieldDef_HasSubDef(const upb_FieldDef* f) { - return upb_FieldDef_IsSubMessage(f) || - upb_FieldDef_CType(f) == kUpb_CType_Enum; -} + // A full validation would also check that each range is disjoint, and that + // none of the fields overlap with the extension ranges, but we are just + // sanity checking here. + if (start < 1 || end <= start || end > max) { + _upb_DefBuilder_Errf(ctx, + "Extension range (%d, %d) is invalid, message=%s\n", + (int)start, (int)end, upb_MessageDef_FullName(m)); + } -bool upb_FieldDef_HasPresence(const upb_FieldDef* f) { - if (upb_FieldDef_IsRepeated(f)) return false; - return upb_FieldDef_IsSubMessage(f) || upb_FieldDef_ContainingOneof(f) || - f->file->syntax == kUpb_Syntax_Proto2; -} + r[i].start = start; + r[i].end = end; + UBP_DEF_SET_OPTIONS(r[i].opts, DescriptorProto_ExtensionRange, + ExtensionRangeOptions, protos[i]); + } -static bool between(int32_t x, int32_t low, int32_t high) { - return x >= low && x <= high; + return r; } -bool upb_FieldDef_checklabel(int32_t label) { return between(label, 1, 3); } -bool upb_FieldDef_checktype(int32_t type) { return between(type, 1, 11); } -bool upb_FieldDef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); } - -bool upb_FieldDef_checkdescriptortype(int32_t type) { - return between(type, 1, 18); -} -/* upb_MessageDef - * *****************************************************************/ +#include +#include -const google_protobuf_MessageOptions* upb_MessageDef_Options( - const upb_MessageDef* m) { - return m->opts; -} -bool upb_MessageDef_HasOptions(const upb_MessageDef* m) { - return m->opts != (void*)opt_default; -} +// Must be last. -const char* upb_MessageDef_FullName(const upb_MessageDef* m) { - return m->full_name; -} +#define UPB_FIELD_TYPE_UNSPECIFIED 0 -const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m) { - return m->file; -} +typedef struct { + size_t len; + char str[1]; // Null-terminated string data follows. +} str_t; -const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m) { - return m->containing_type; -} +struct upb_FieldDef { + const google_protobuf_FieldOptions* opts; + const upb_FileDef* file; + const upb_MessageDef* msgdef; + const char* full_name; + const char* json_name; + union { + int64_t sint; + uint64_t uint; + double dbl; + float flt; + bool boolean; + str_t* str; + } defaultval; + union { + const upb_OneofDef* oneof; + const upb_MessageDef* extension_scope; + } scope; + union { + const upb_MessageDef* msgdef; + const upb_EnumDef* enumdef; + const google_protobuf_FieldDescriptorProto* unresolved; + } sub; + uint32_t number_; + uint16_t index_; + uint16_t layout_index; // Index into msgdef->layout->fields or file->exts + bool has_default; + bool is_extension_; + bool is_packed_; + bool proto3_optional_; + bool has_json_name_; + upb_FieldType type_; + upb_Label label_; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif +}; -const char* upb_MessageDef_Name(const upb_MessageDef* m) { - return shortdefname(m->full_name); +upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i) { + return (upb_FieldDef*)&f[i]; } -upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m) { - return m->file->syntax; +const google_protobuf_FieldOptions* upb_FieldDef_Options(const upb_FieldDef* f) { + return f->opts; } -const upb_FieldDef* upb_MessageDef_FindFieldByNumber(const upb_MessageDef* m, - uint32_t i) { - upb_value val; - return upb_inttable_lookup(&m->itof, i, &val) ? upb_value_getconstptr(val) - : NULL; +bool upb_FieldDef_HasOptions(const upb_FieldDef* f) { + return f->opts != (void*)kUpbDefOptDefault; } -const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( - const upb_MessageDef* m, const char* name, size_t len) { - upb_value val; - - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return NULL; - } - - return unpack_def(val, UPB_DEFTYPE_FIELD); +const char* upb_FieldDef_FullName(const upb_FieldDef* f) { + return f->full_name; } -const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( - const upb_MessageDef* m, const char* name, size_t len) { - upb_value val; - - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return NULL; +upb_CType upb_FieldDef_CType(const upb_FieldDef* f) { + switch (f->type_) { + case kUpb_FieldType_Double: + return kUpb_CType_Double; + case kUpb_FieldType_Float: + return kUpb_CType_Float; + case kUpb_FieldType_Int64: + case kUpb_FieldType_SInt64: + case kUpb_FieldType_SFixed64: + return kUpb_CType_Int64; + case kUpb_FieldType_Int32: + case kUpb_FieldType_SFixed32: + case kUpb_FieldType_SInt32: + return kUpb_CType_Int32; + case kUpb_FieldType_UInt64: + case kUpb_FieldType_Fixed64: + return kUpb_CType_UInt64; + case kUpb_FieldType_UInt32: + case kUpb_FieldType_Fixed32: + return kUpb_CType_UInt32; + case kUpb_FieldType_Enum: + return kUpb_CType_Enum; + case kUpb_FieldType_Bool: + return kUpb_CType_Bool; + case kUpb_FieldType_String: + return kUpb_CType_String; + case kUpb_FieldType_Bytes: + return kUpb_CType_Bytes; + case kUpb_FieldType_Group: + case kUpb_FieldType_Message: + return kUpb_CType_Message; } - - return unpack_def(val, UPB_DEFTYPE_ONEOF); + UPB_UNREACHABLE(); } -bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, - const char* name, size_t len, - const upb_FieldDef** out_f, - const upb_OneofDef** out_o) { - upb_value val; - - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return false; - } - - const upb_FieldDef* f = unpack_def(val, UPB_DEFTYPE_FIELD); - const upb_OneofDef* o = unpack_def(val, UPB_DEFTYPE_ONEOF); - if (out_f) *out_f = f; - if (out_o) *out_o = o; - return f || o; /* False if this was a JSON name. */ -} +upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f) { return f->type_; } -const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( - const upb_MessageDef* m, const char* name, size_t len) { - upb_value val; - const upb_FieldDef* f; +uint32_t upb_FieldDef_Index(const upb_FieldDef* f) { return f->index_; } - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return NULL; - } +upb_Label upb_FieldDef_Label(const upb_FieldDef* f) { return f->label_; } - f = unpack_def(val, UPB_DEFTYPE_FIELD); - if (!f) f = unpack_def(val, UPB_DEFTYPE_FIELD_JSONNAME); +uint32_t upb_FieldDef_Number(const upb_FieldDef* f) { return f->number_; } - return f; +bool upb_FieldDef_IsExtension(const upb_FieldDef* f) { + return f->is_extension_; } -int upb_MessageDef_numfields(const upb_MessageDef* m) { return m->field_count; } - -int upb_MessageDef_numoneofs(const upb_MessageDef* m) { return m->oneof_count; } +bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { return f->is_packed_; } -int upb_MessageDef_numrealoneofs(const upb_MessageDef* m) { - return m->real_oneof_count; -} - -int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) { - return m->ext_range_count; +const char* upb_FieldDef_Name(const upb_FieldDef* f) { + return _upb_DefBuilder_FullToShort(f->full_name); } -int upb_MessageDef_FieldCount(const upb_MessageDef* m) { - return m->field_count; +const char* upb_FieldDef_JsonName(const upb_FieldDef* f) { + return f->json_name; } -int upb_MessageDef_OneofCount(const upb_MessageDef* m) { - return m->oneof_count; +bool upb_FieldDef_HasJsonName(const upb_FieldDef* f) { + return f->has_json_name_; } -int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m) { - return m->nested_msg_count; -} +const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f) { return f->file; } -int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m) { - return m->nested_enum_count; +const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f) { + return f->msgdef; } -int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m) { - return m->nested_ext_count; +const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f) { + return f->is_extension_ ? f->scope.extension_scope : NULL; } -int upb_MessageDef_realoneofcount(const upb_MessageDef* m) { - return m->real_oneof_count; +const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f) { + return f->is_extension_ ? NULL : f->scope.oneof; } -const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m) { - return m->layout; +const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f) { + const upb_OneofDef* oneof = upb_FieldDef_ContainingOneof(f); + if (!oneof || upb_OneofDef_IsSynthetic(oneof)) return NULL; + return oneof; } -const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, - int i) { - UPB_ASSERT(0 <= i && i < m->ext_range_count); - return &m->ext_ranges[i]; -} +upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f) { + UPB_ASSERT(!upb_FieldDef_IsSubMessage(f)); + upb_MessageValue ret; -const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->field_count); - return &m->fields[i]; -} + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + return (upb_MessageValue){.bool_val = f->defaultval.boolean}; + case kUpb_CType_Int64: + return (upb_MessageValue){.int64_val = f->defaultval.sint}; + case kUpb_CType_UInt64: + return (upb_MessageValue){.uint64_val = f->defaultval.uint}; + case kUpb_CType_Enum: + case kUpb_CType_Int32: + return (upb_MessageValue){.int32_val = (int32_t)f->defaultval.sint}; + case kUpb_CType_UInt32: + return (upb_MessageValue){.uint32_val = (uint32_t)f->defaultval.uint}; + case kUpb_CType_Float: + return (upb_MessageValue){.float_val = f->defaultval.flt}; + case kUpb_CType_Double: + return (upb_MessageValue){.double_val = f->defaultval.dbl}; + case kUpb_CType_String: + case kUpb_CType_Bytes: { + str_t* str = f->defaultval.str; + if (str) { + return (upb_MessageValue){ + .str_val = (upb_StringView){.data = str->str, .size = str->len}}; + } else { + return (upb_MessageValue){ + .str_val = (upb_StringView){.data = NULL, .size = 0}}; + } + } + default: + UPB_UNREACHABLE(); + } -const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->oneof_count); - return &m->oneofs[i]; + return ret; } -const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, - int i) { - UPB_ASSERT(0 <= i && i < m->nested_msg_count); - return &m->nested_msgs[i]; +const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Message ? f->sub.msgdef : NULL; } -const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->nested_enum_count); - return &m->nested_enums[i]; +const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Enum ? f->sub.enumdef : NULL; } -const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, - int i) { - UPB_ASSERT(0 <= i && i < m->nested_ext_count); - return &m->nested_exts[i]; +const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f) { + UPB_ASSERT(!upb_FieldDef_IsExtension(f)); + const upb_MiniTable* layout = upb_MessageDef_MiniTable(f->msgdef); + return &layout->fields[f->layout_index]; } -upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m) { - return m->well_known_type; +const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable( + const upb_FieldDef* f) { + UPB_ASSERT(upb_FieldDef_IsExtension(f)); + const upb_FileDef* file = upb_FieldDef_File(f); + return _upb_FileDef_ExtensionMiniTable(file, f->layout_index); } -/* upb_OneofDef ***************************************************************/ +bool _upb_FieldDef_IsClosedEnum(const upb_FieldDef* f) { + if (UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3) return false; + if (f->type_ != kUpb_FieldType_Enum) return false; -const google_protobuf_OneofOptions* upb_OneofDef_Options( - const upb_OneofDef* o) { - return o->opts; -} - -bool upb_OneofDef_HasOptions(const upb_OneofDef* o) { - return o->opts != (void*)opt_default; -} + // TODO(https://github.com/protocolbuffers/upb/issues/541): + // fix map enum values to check for unknown enum values and put + // them in the unknown field set. + if (upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f))) { + return false; + } -const char* upb_OneofDef_Name(const upb_OneofDef* o) { - return shortdefname(o->full_name); + // TODO: Maybe make is_proto2 a bool at creation? + const upb_FileDef* file = upb_EnumDef_File(f->sub.enumdef); + return upb_FileDef_Syntax(file) == kUpb_Syntax_Proto2; } -const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o) { - return o->parent; +bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) { + return f->proto3_optional_; } -int upb_OneofDef_FieldCount(const upb_OneofDef* o) { return o->field_count; } +int _upb_FieldDef_LayoutIndex(const upb_FieldDef* f) { return f->layout_index; } -const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i) { - UPB_ASSERT(i < o->field_count); - return o->fields[i]; -} +uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f) { + uint64_t out = f->is_packed_ ? kUpb_FieldModifier_IsPacked : 0; -int upb_OneofDef_numfields(const upb_OneofDef* o) { return o->field_count; } + switch (f->label_) { + case kUpb_Label_Optional: + if (!upb_FieldDef_HasPresence(f)) { + out |= kUpb_FieldModifier_IsProto3Singular; + } + break; + case kUpb_Label_Repeated: + out |= kUpb_FieldModifier_IsRepeated; + break; + case kUpb_Label_Required: + out |= kUpb_FieldModifier_IsRequired; + break; + } -uint32_t upb_OneofDef_Index(const upb_OneofDef* o) { - // Compute index in our parent's array. - return o - o->parent->oneofs; + if (_upb_FieldDef_IsClosedEnum(f)) { + out |= kUpb_FieldModifier_IsClosedEnum; + } + return out; } -bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o) { return o->synthetic; } - -const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, - const char* name, - size_t length) { - upb_value val; - return upb_strtable_lookup2(&o->ntof, name, length, &val) - ? upb_value_getptr(val) - : NULL; -} +bool upb_FieldDef_HasDefault(const upb_FieldDef* f) { return f->has_default; } -const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, - uint32_t num) { - upb_value val; - return upb_inttable_lookup(&o->itof, num, &val) ? upb_value_getptr(val) - : NULL; +bool upb_FieldDef_HasPresence(const upb_FieldDef* f) { + if (upb_FieldDef_IsRepeated(f)) return false; + const upb_FileDef* file = upb_FieldDef_File(f); + return upb_FieldDef_IsSubMessage(f) || upb_FieldDef_ContainingOneof(f) || + upb_FileDef_Syntax(file) == kUpb_Syntax_Proto2; } -/* upb_FileDef ****************************************************************/ - -const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f) { - return f->opts; +bool upb_FieldDef_HasSubDef(const upb_FieldDef* f) { + return upb_FieldDef_IsSubMessage(f) || + upb_FieldDef_CType(f) == kUpb_CType_Enum; } -bool upb_FileDef_HasOptions(const upb_FileDef* f) { - return f->opts != (void*)opt_default; +bool upb_FieldDef_IsMap(const upb_FieldDef* f) { + return upb_FieldDef_IsRepeated(f) && upb_FieldDef_IsSubMessage(f) && + upb_MessageDef_IsMapEntry(upb_FieldDef_MessageSubDef(f)); } -const char* upb_FileDef_Name(const upb_FileDef* f) { return f->name; } - -const char* upb_FileDef_Package(const upb_FileDef* f) { return f->package; } - -upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f) { return f->syntax; } - -int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f) { - return f->top_lvl_msg_count; +bool upb_FieldDef_IsOptional(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Optional; } -int upb_FileDef_DependencyCount(const upb_FileDef* f) { return f->dep_count; } - -int upb_FileDef_PublicDependencyCount(const upb_FileDef* f) { - return f->public_dep_count; +bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f) { + return !upb_FieldDef_IsString(f) && !upb_FieldDef_IsSubMessage(f); } -int upb_FileDef_WeakDependencyCount(const upb_FileDef* f) { - return f->weak_dep_count; +bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Repeated; } -const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f) { - return f->public_deps; +bool upb_FieldDef_IsRequired(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Required; } -const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f) { - return f->weak_deps; +bool upb_FieldDef_IsString(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_String || + upb_FieldDef_CType(f) == kUpb_CType_Bytes; } -int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f) { - return f->top_lvl_enum_count; +bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Message; } -int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f) { - return f->top_lvl_ext_count; +static bool between(int32_t x, int32_t low, int32_t high) { + return x >= low && x <= high; } -int upb_FileDef_ServiceCount(const upb_FileDef* f) { return f->service_count; } +bool upb_FieldDef_checklabel(int32_t label) { return between(label, 1, 3); } +bool upb_FieldDef_checktype(int32_t type) { return between(type, 1, 11); } +bool upb_FieldDef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); } -const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->dep_count); - return f->deps[i]; +bool upb_FieldDef_checkdescriptortype(int32_t type) { + return between(type, 1, 18); } -const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->public_dep_count); - return f->deps[f->public_deps[i]]; +static bool streql2(const char* a, size_t n, const char* b) { + return n == strlen(b) && memcmp(a, b, n) == 0; } -const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->public_dep_count); - return f->deps[f->weak_deps[i]]; -} +// Implement the transformation as described in the spec: +// 1. upper case all letters after an underscore. +// 2. remove all underscores. +static char* make_json_name(const char* name, size_t size, upb_Arena* a) { + char* out = upb_Arena_Malloc(a, size + 1); // +1 is to add a trailing '\0' + if (out == NULL) return NULL; -const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->top_lvl_msg_count); - return &f->top_lvl_msgs[i]; + bool ucase_next = false; + char* des = out; + for (size_t i = 0; i < size; i++) { + if (name[i] == '_') { + ucase_next = true; + } else { + *des++ = ucase_next ? toupper(name[i]) : name[i]; + ucase_next = false; + } + } + *des++ = '\0'; + return out; } -const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->top_lvl_enum_count); - return &f->top_lvl_enums[i]; +static str_t* newstr(upb_DefBuilder* ctx, const char* data, size_t len) { + str_t* ret = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); + if (!ret) _upb_DefBuilder_OomErr(ctx); + ret->len = len; + if (len) memcpy(ret->str, data, len); + ret->str[len] = '\0'; + return ret; } -const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->top_lvl_ext_count); - return &f->top_lvl_exts[i]; -} +static str_t* unescape(upb_DefBuilder* ctx, const upb_FieldDef* f, + const char* data, size_t len) { + // Size here is an upper bound; escape sequences could ultimately shrink it. + str_t* ret = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); + char* dst = &ret->str[0]; + const char* src = data; + const char* end = data + len; -const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->service_count); - return &f->services[i]; + while (src < end) { + if (*src == '\\') { + src++; + *dst++ = _upb_DefBuilder_ParseEscape(ctx, f, &src, end); + } else { + *dst++ = *src++; + } + } + + ret->len = dst - &ret->str[0]; + return ret; } -const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f) { return f->symtab; } +static void parse_default(upb_DefBuilder* ctx, const char* str, size_t len, + upb_FieldDef* f) { + char* end; + char nullz[64]; + errno = 0; -/* upb_MethodDef **************************************************************/ + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Int32: + case kUpb_CType_Int64: + case kUpb_CType_UInt32: + case kUpb_CType_UInt64: + case kUpb_CType_Double: + case kUpb_CType_Float: + /* Standard C number parsing functions expect null-terminated strings. */ + if (len >= sizeof(nullz) - 1) { + _upb_DefBuilder_Errf(ctx, "Default too long: %.*s", (int)len, str); + } + memcpy(nullz, str, len); + nullz[len] = '\0'; + str = nullz; + break; + default: + break; + } -const google_protobuf_MethodOptions* upb_MethodDef_Options( - const upb_MethodDef* m) { - return m->opts; -} + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Int32: { + long val = strtol(str, &end, 0); + if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.sint = val; + break; + } + case kUpb_CType_Enum: { + const upb_EnumDef* e = f->sub.enumdef; + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByNameWithSize(e, str, len); + if (!ev) { + goto invalid; + } + f->defaultval.sint = upb_EnumValueDef_Number(ev); + break; + } + case kUpb_CType_Int64: { + long long val = strtoll(str, &end, 0); + if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.sint = val; + break; + } + case kUpb_CType_UInt32: { + unsigned long val = strtoul(str, &end, 0); + if (val > UINT32_MAX || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.uint = val; + break; + } + case kUpb_CType_UInt64: { + unsigned long long val = strtoull(str, &end, 0); + if (val > UINT64_MAX || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.uint = val; + break; + } + case kUpb_CType_Double: { + double val = strtod(str, &end); + if (errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.dbl = val; + break; + } + case kUpb_CType_Float: { + float val = strtof(str, &end); + if (errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.flt = val; + break; + } + case kUpb_CType_Bool: { + if (streql2(str, len, "false")) { + f->defaultval.boolean = false; + } else if (streql2(str, len, "true")) { + f->defaultval.boolean = true; + } else { + goto invalid; + } + break; + } + case kUpb_CType_String: + f->defaultval.str = newstr(ctx, str, len); + break; + case kUpb_CType_Bytes: + f->defaultval.str = unescape(ctx, f, str, len); + break; + case kUpb_CType_Message: + /* Should not have a default value. */ + _upb_DefBuilder_Errf(ctx, "Message should not have a default (%s)", + upb_FieldDef_FullName(f)); + } -bool upb_MethodDef_HasOptions(const upb_MethodDef* m) { - return m->opts != (void*)opt_default; + return; + +invalid: + _upb_DefBuilder_Errf(ctx, "Invalid default '%.*s' for field %s of type %d", + (int)len, str, upb_FieldDef_FullName(f), + (int)upb_FieldDef_Type(f)); } -const char* upb_MethodDef_FullName(const upb_MethodDef* m) { - return m->full_name; +static void set_default_default(upb_DefBuilder* ctx, upb_FieldDef* f) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Int32: + case kUpb_CType_Int64: + f->defaultval.sint = 0; + break; + case kUpb_CType_UInt64: + case kUpb_CType_UInt32: + f->defaultval.uint = 0; + break; + case kUpb_CType_Double: + case kUpb_CType_Float: + f->defaultval.dbl = 0; + break; + case kUpb_CType_String: + case kUpb_CType_Bytes: + f->defaultval.str = newstr(ctx, NULL, 0); + break; + case kUpb_CType_Bool: + f->defaultval.boolean = false; + break; + case kUpb_CType_Enum: { + const upb_EnumValueDef* v = upb_EnumDef_Value(f->sub.enumdef, 0); + f->defaultval.sint = upb_EnumValueDef_Number(v); + } + case kUpb_CType_Message: + break; + } } -int upb_MethodDef_Index(const upb_MethodDef* m) { return m->index; } +static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_FieldDescriptorProto* field_proto, + upb_MessageDef* m, upb_FieldDef* f) { + // Must happen before _upb_DefBuilder_Add() + f->file = _upb_DefBuilder_File(ctx); -const char* upb_MethodDef_Name(const upb_MethodDef* m) { - return shortdefname(m->full_name); -} + if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { + _upb_DefBuilder_Errf(ctx, "field has no name"); + } -const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m) { - return m->service; -} + const upb_StringView name = google_protobuf_FieldDescriptorProto_name(field_proto); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); -const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m) { - return m->input_type; -} + f->has_json_name_ = google_protobuf_FieldDescriptorProto_has_json_name(field_proto); + if (f->has_json_name_) { + const upb_StringView sv = + google_protobuf_FieldDescriptorProto_json_name(field_proto); + f->json_name = upb_strdup2(sv.data, sv.size, ctx->arena); + } else { + f->json_name = make_json_name(name.data, name.size, ctx->arena); + } + if (!f->json_name) _upb_DefBuilder_OomErr(ctx); -const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m) { - return m->output_type; -} + f->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto); + f->number_ = google_protobuf_FieldDescriptorProto_number(field_proto); + f->proto3_optional_ = + google_protobuf_FieldDescriptorProto_proto3_optional(field_proto); + f->msgdef = m; + f->scope.oneof = NULL; -bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m) { - return m->client_streaming; -} + const bool has_type = google_protobuf_FieldDescriptorProto_has_type(field_proto); + const bool has_type_name = + google_protobuf_FieldDescriptorProto_has_type_name(field_proto); -bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { - return m->server_streaming; -} + f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto); + + if (has_type) { + switch (f->type_) { + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + case kUpb_FieldType_Enum: + if (!has_type_name) { + _upb_DefBuilder_Errf(ctx, "field of type %d requires type name (%s)", + (int)f->type_, f->full_name); + } + break; + default: + if (has_type_name) { + _upb_DefBuilder_Errf( + ctx, "invalid type for field with type_name set (%s, %d)", + f->full_name, (int)f->type_); + } + } + } else if (has_type_name) { + f->type_ = + UPB_FIELD_TYPE_UNSPECIFIED; // We'll fill this in in resolve_fielddef() + } + + if (f->type_ < kUpb_FieldType_Double || f->type_ > kUpb_FieldType_SInt64) { + _upb_DefBuilder_Errf(ctx, "invalid type for field %s (%d)", f->full_name, + f->type_); + } -/* upb_ServiceDef *************************************************************/ + if (f->label_ < kUpb_Label_Optional || f->label_ > kUpb_Label_Repeated) { + _upb_DefBuilder_Errf(ctx, "invalid label for field %s (%d)", f->full_name, + f->label_); + } + + /* We can't resolve the subdef or (in the case of extensions) the containing + * message yet, because it may not have been defined yet. We stash a pointer + * to the field_proto until later when we can properly resolve it. */ + f->sub.unresolved = field_proto; -const google_protobuf_ServiceOptions* upb_ServiceDef_Options( - const upb_ServiceDef* s) { - return s->opts; -} + if (f->label_ == kUpb_Label_Required && + upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3) { + _upb_DefBuilder_Errf(ctx, "proto3 fields cannot be required (%s)", + f->full_name); + } -bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s) { - return s->opts != (void*)opt_default; -} + if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + uint32_t oneof_index = google_protobuf_FieldDescriptorProto_oneof_index(field_proto); -const char* upb_ServiceDef_FullName(const upb_ServiceDef* s) { - return s->full_name; -} + if (upb_FieldDef_Label(f) != kUpb_Label_Optional) { + _upb_DefBuilder_Errf(ctx, "fields in oneof must have OPTIONAL label (%s)", + f->full_name); + } -const char* upb_ServiceDef_Name(const upb_ServiceDef* s) { - return shortdefname(s->full_name); -} + if (!m) { + _upb_DefBuilder_Errf(ctx, "oneof field (%s) has no containing msg", + f->full_name); + } -int upb_ServiceDef_Index(const upb_ServiceDef* s) { return s->index; } + if (oneof_index >= upb_MessageDef_OneofCount(m)) { + _upb_DefBuilder_Errf(ctx, "oneof_index out of range (%s)", f->full_name); + } -const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s) { - return s->file; -} + upb_OneofDef* oneof = (upb_OneofDef*)upb_MessageDef_Oneof(m, oneof_index); + f->scope.oneof = oneof; -int upb_ServiceDef_MethodCount(const upb_ServiceDef* s) { - return s->method_count; -} + bool ok = _upb_OneofDef_Insert(oneof, f, name.data, name.size, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + } -const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i) { - return i < 0 || i >= s->method_count ? NULL : &s->methods[i]; -} + UBP_DEF_SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); -const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, - const char* name) { - for (int i = 0; i < s->method_count; i++) { - if (strcmp(name, upb_MethodDef_Name(&s->methods[i])) == 0) { - return &s->methods[i]; - } + if (google_protobuf_FieldOptions_has_packed(f->opts)) { + f->is_packed_ = google_protobuf_FieldOptions_packed(f->opts); + } else { + // Repeated fields default to packed for proto3 only. + f->is_packed_ = upb_FieldDef_IsPrimitive(f) && + f->label_ == kUpb_Label_Repeated && + upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3; } - return NULL; } -/* upb_DefPool ****************************************************************/ +static void _upb_FieldDef_CreateExt( + upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m, + upb_FieldDef* f) { + _upb_FieldDef_Create(ctx, prefix, field_proto, m, f); + f->is_extension_ = true; -void upb_DefPool_Free(upb_DefPool* s) { - upb_Arena_Free(s->arena); - upb_gfree(s); -} + if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + _upb_DefBuilder_Errf(ctx, "oneof_index provided for extension field (%s)", + f->full_name); + } -upb_DefPool* upb_DefPool_New(void) { - upb_DefPool* s = upb_gmalloc(sizeof(*s)); + f->scope.extension_scope = m; + _upb_DefBuilder_Add(ctx, f->full_name, _upb_DefType_Pack(f, UPB_DEFTYPE_EXT)); + f->layout_index = ctx->ext_count++; - if (!s) { - return NULL; + if (ctx->layout) { + UPB_ASSERT(_upb_FieldDef_ExtensionMiniTable(f)->field.number == f->number_); } +} - s->arena = upb_Arena_New(); - s->bytes_loaded = 0; +static void _upb_FieldDef_CreateNotExt( + upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m, + upb_FieldDef* f) { + _upb_FieldDef_Create(ctx, prefix, field_proto, m, f); + f->is_extension_ = false; - if (!upb_strtable_init(&s->syms, 32, s->arena) || - !upb_strtable_init(&s->files, 4, s->arena) || - !upb_inttable_init(&s->exts, s->arena)) { - goto err; + if (!google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + if (f->proto3_optional_) { + _upb_DefBuilder_Errf( + ctx, + "non-extension field (%s) with proto3_optional was not in a oneof", + f->full_name); + } } - s->extreg = upb_ExtensionRegistry_New(s->arena); - if (!s->extreg) goto err; - return s; + _upb_MessageDef_InsertField(ctx, m, f); -err: - upb_Arena_Free(s->arena); - upb_gfree(s); - return NULL; -} + if (!ctx->layout) return; -static const void* symtab_lookup(const upb_DefPool* s, const char* sym, - upb_deftype_t type) { - upb_value v; - return upb_strtable_lookup(&s->syms, sym, &v) ? unpack_def(v, type) : NULL; -} + const upb_MiniTable* mt = upb_MessageDef_MiniTable(m); + const upb_MiniTable_Field* fields = mt->fields; + for (int i = 0; i < mt->field_count; i++) { + if (fields[i].number == f->number_) { + f->layout_index = i; + return; + } + } -static const void* symtab_lookup2(const upb_DefPool* s, const char* sym, - size_t size, upb_deftype_t type) { - upb_value v; - return upb_strtable_lookup2(&s->syms, sym, size, &v) ? unpack_def(v, type) - : NULL; + UPB_ASSERT(false); // It should be impossible to reach this point. } -const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, - const char* sym) { - return symtab_lookup(s, sym, UPB_DEFTYPE_MSG); -} +upb_FieldDef* _upb_FieldDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_FieldDescriptorProto* const* protos, const char* prefix, + upb_MessageDef* m, bool* is_sorted) { + _upb_DefType_CheckPadding(sizeof(upb_FieldDef)); + upb_FieldDef* defs = + (upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n); -const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( - const upb_DefPool* s, const char* sym, size_t len) { - return symtab_lookup2(s, sym, len, UPB_DEFTYPE_MSG); -} + // If we are creating extensions then is_sorted will be NULL. + // If we are not creating extensions then is_sorted will be non-NULL. + if (is_sorted) { + uint32_t previous = 0; + for (int i = 0; i < n; i++) { + upb_FieldDef* f = &defs[i]; -const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, - const char* sym) { - return symtab_lookup(s, sym, UPB_DEFTYPE_ENUM); -} + _upb_FieldDef_CreateNotExt(ctx, prefix, protos[i], m, f); + f->index_ = i; + if (!ctx->layout) f->layout_index = i; -const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, - const char* sym) { - return symtab_lookup(s, sym, UPB_DEFTYPE_ENUMVAL); -} + const uint32_t current = f->number_; + if (previous > current) *is_sorted = false; + previous = current; + } + } else { + for (int i = 0; i < n; i++) { + upb_FieldDef* f = &defs[i]; -const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, - const char* name) { - upb_value v; - return upb_strtable_lookup(&s->files, name, &v) - ? unpack_def(v, UPB_DEFTYPE_FILE) - : NULL; -} + _upb_FieldDef_CreateExt(ctx, prefix, protos[i], m, f); + f->index_ = i; + } + } -const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, - const char* name, - size_t len) { - upb_value v; - return upb_strtable_lookup2(&s->files, name, len, &v) - ? unpack_def(v, UPB_DEFTYPE_FILE) - : NULL; + return defs; } -const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( - const upb_DefPool* s, const char* name, size_t size) { - upb_value v; - if (!upb_strtable_lookup2(&s->syms, name, size, &v)) return NULL; - - switch (deftype(v)) { - case UPB_DEFTYPE_FIELD: - return unpack_def(v, UPB_DEFTYPE_FIELD); - case UPB_DEFTYPE_MSG: { - const upb_MessageDef* m = unpack_def(v, UPB_DEFTYPE_MSG); - return m->in_message_set ? &m->nested_exts[0] : NULL; +static void resolve_subdef(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f) { + const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; + upb_StringView name = + google_protobuf_FieldDescriptorProto_type_name(field_proto); + bool has_name = + google_protobuf_FieldDescriptorProto_has_type_name(field_proto); + switch ((int)f->type_) { + case UPB_FIELD_TYPE_UNSPECIFIED: { + // Type was not specified and must be inferred. + UPB_ASSERT(has_name); + upb_deftype_t type; + const void* def = + _upb_DefBuilder_ResolveAny(ctx, f->full_name, prefix, name, &type); + switch (type) { + case UPB_DEFTYPE_ENUM: + f->sub.enumdef = def; + f->type_ = kUpb_FieldType_Enum; + break; + case UPB_DEFTYPE_MSG: + f->sub.msgdef = def; + f->type_ = kUpb_FieldType_Message; // It appears there is no way of + // this being a group. + break; + default: + _upb_DefBuilder_Errf(ctx, "Couldn't resolve type name for field %s", + f->full_name); + } } + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + UPB_ASSERT(has_name); + f->sub.msgdef = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, + UPB_DEFTYPE_MSG); + break; + case kUpb_FieldType_Enum: + UPB_ASSERT(has_name); + f->sub.enumdef = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, + UPB_DEFTYPE_ENUM); + break; default: + // No resolution necessary. break; } - - return NULL; -} - -const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, - const char* sym) { - return upb_DefPool_FindExtensionByNameWithSize(s, sym, strlen(sym)); } -const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, - const char* name) { - return symtab_lookup(s, name, UPB_DEFTYPE_SERVICE); +static int _upb_FieldDef_Compare(const void* p1, const void* p2) { + const uint32_t v1 = (*(upb_FieldDef**)p1)->number_; + const uint32_t v2 = (*(upb_FieldDef**)p2)->number_; + return (v1 < v2) ? -1 : (v1 > v2); } -const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( - const upb_DefPool* s, const char* name, size_t size) { - return symtab_lookup2(s, name, size, UPB_DEFTYPE_SERVICE); -} +const upb_FieldDef** _upb_FieldDefs_Sorted(const upb_FieldDef* f, int n, + upb_Arena* a) { + // TODO: Try to replace this arena alloc with a persistent scratch buffer. + upb_FieldDef** out = (upb_FieldDef**)upb_Arena_Malloc(a, n * sizeof(void*)); + if (!out) return NULL; -const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, - const char* name) { - upb_value v; - // TODO(haberman): non-extension fields and oneofs. - if (upb_strtable_lookup(&s->syms, name, &v)) { - switch (deftype(v)) { - case UPB_DEFTYPE_EXT: { - const upb_FieldDef* f = unpack_def(v, UPB_DEFTYPE_EXT); - return upb_FieldDef_File(f); - } - case UPB_DEFTYPE_MSG: { - const upb_MessageDef* m = unpack_def(v, UPB_DEFTYPE_MSG); - return upb_MessageDef_File(m); - } - case UPB_DEFTYPE_ENUM: { - const upb_EnumDef* e = unpack_def(v, UPB_DEFTYPE_ENUM); - return upb_EnumDef_File(e); - } - case UPB_DEFTYPE_ENUMVAL: { - const upb_EnumValueDef* ev = unpack_def(v, UPB_DEFTYPE_ENUMVAL); - return upb_EnumDef_File(upb_EnumValueDef_Enum(ev)); - } - case UPB_DEFTYPE_SERVICE: { - const upb_ServiceDef* service = unpack_def(v, UPB_DEFTYPE_SERVICE); - return upb_ServiceDef_File(service); - } - default: - UPB_UNREACHABLE(); - } + for (int i = 0; i < n; i++) { + out[i] = (upb_FieldDef*)&f[i]; } + qsort(out, n, sizeof(void*), _upb_FieldDef_Compare); - const char* last_dot = strrchr(name, '.'); - if (last_dot) { - const upb_MessageDef* parent = - upb_DefPool_FindMessageByNameWithSize(s, name, last_dot - name); - if (parent) { - const char* shortname = last_dot + 1; - if (upb_MessageDef_FindByNameWithSize(parent, shortname, - strlen(shortname), NULL, NULL)) { - return upb_MessageDef_File(parent); - } - } + for (int i = 0; i < n; i++) { + out[i]->layout_index = i; } - - return NULL; + return (const upb_FieldDef**)out; } -/* Code to build defs from descriptor protos. *********************************/ +bool upb_FieldDef_MiniDescriptorEncode(const upb_FieldDef* f, upb_Arena* a, + upb_StringView* out) { + UPB_ASSERT(f->is_extension_); -/* There is a question of how much validation to do here. It will be difficult - * to perfectly match the amount of validation performed by proto2. But since - * this code is used to directly build defs from Ruby (for example) we do need - * to validate important constraints like uniqueness of names and numbers. */ + upb_DescState s; + _upb_DescState_Init(&s); -#define CHK_OOM(x) \ - if (!(x)) { \ - symtab_oomerr(ctx); \ - } + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_StartMessage(&s.e, s.ptr, 0); -typedef struct { - upb_DefPool* symtab; - upb_FileDef* file; /* File we are building. */ - upb_Arena* arena; /* Allocate defs here. */ - upb_Arena* tmp_arena; /* For temporary allocations. */ - const upb_MiniTable_File* layout; /* NULL if we should build layouts. */ - int enum_count; /* Count of enums built so far. */ - int msg_count; /* Count of messages built so far. */ - int ext_count; /* Count of extensions built so far. */ - upb_Status* status; /* Record errors here. */ - jmp_buf err; /* longjmp() on error. */ -} symtab_addctx; - -UPB_NORETURN UPB_NOINLINE UPB_PRINTF(2, 3) static void symtab_errf( - symtab_addctx* ctx, const char* fmt, ...) { - va_list argp; - va_start(argp, fmt); - upb_Status_VSetErrorFormat(ctx->status, fmt, argp); - va_end(argp); - UPB_LONGJMP(ctx->err, 1); -} + const int number = upb_FieldDef_Number(f); + const uint64_t modifiers = _upb_FieldDef_Modifiers(f); -UPB_NORETURN UPB_NOINLINE static void symtab_oomerr(symtab_addctx* ctx) { - upb_Status_setoom(ctx->status); - UPB_LONGJMP(ctx->err, 1); -} + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_PutField(&s.e, s.ptr, f->type_, number, modifiers); -void* symtab_alloc(symtab_addctx* ctx, size_t bytes) { - if (bytes == 0) return NULL; - void* ret = upb_Arena_Malloc(ctx->arena, bytes); - if (!ret) symtab_oomerr(ctx); - return ret; + if (!_upb_DescState_Grow(&s, a)) return false; + *s.ptr = '\0'; + + out->data = s.buf; + out->size = s.ptr - s.buf; + return true; } -// We want to copy the options verbatim into the destination options proto. -// We use serialize+parse as our deep copy. -#define SET_OPTIONS(target, desc_type, options_type, proto) \ - if (google_protobuf_##desc_type##_has_options(proto)) { \ - size_t size; \ - char* pb = google_protobuf_##options_type##_serialize( \ - google_protobuf_##desc_type##_options(proto), ctx->tmp_arena, &size); \ - CHK_OOM(pb); \ - target = google_protobuf_##options_type##_parse(pb, size, ctx->arena); \ - CHK_OOM(target); \ - } else { \ - target = (const google_protobuf_##options_type*)opt_default; \ +static void resolve_extension(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f, + const google_protobuf_FieldDescriptorProto* field_proto) { + if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) { + _upb_DefBuilder_Errf(ctx, "extension for field '%s' had no extendee", + f->full_name); } -static void check_ident(symtab_addctx* ctx, upb_StringView name, bool full) { - const char* str = name.data; - size_t len = name.size; - bool start = true; - size_t i; - for (i = 0; i < len; i++) { - char c = str[i]; - if (c == '.') { - if (start || !full) { - symtab_errf(ctx, "invalid name: unexpected '.' (%.*s)", (int)len, str); - } - start = true; - } else if (start) { - if (!upb_isletter(c)) { - symtab_errf( - ctx, - "invalid name: path components must start with a letter (%.*s)", - (int)len, str); - } - start = false; - } else { - if (!upb_isalphanum(c)) { - symtab_errf(ctx, "invalid name: non-alphanumeric character (%.*s)", - (int)len, str); - } - } - } - if (start) { - symtab_errf(ctx, "invalid name: empty part (%.*s)", (int)len, str); + upb_StringView name = google_protobuf_FieldDescriptorProto_extendee(field_proto); + const upb_MessageDef* m = + _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); + f->msgdef = m; + + if (!_upb_MessageDef_IsValidExtensionNumber(m, f->number_)) { + _upb_DefBuilder_Errf( + ctx, + "field number %u in extension %s has no extension range in message %s", + (unsigned)f->number_, f->full_name, upb_MessageDef_FullName(m)); } -} -static size_t div_round_up(size_t n, size_t d) { return (n + d - 1) / d; } + const upb_MiniTable_Extension* ext = _upb_FieldDef_ExtensionMiniTable(f); -static size_t upb_MessageValue_sizeof(upb_CType type) { - switch (type) { - case kUpb_CType_Double: - case kUpb_CType_Int64: - case kUpb_CType_UInt64: - return 8; - case kUpb_CType_Enum: - case kUpb_CType_Int32: - case kUpb_CType_UInt32: - case kUpb_CType_Float: - return 4; - case kUpb_CType_Bool: - return 1; - case kUpb_CType_Message: - return sizeof(void*); - case kUpb_CType_Bytes: - case kUpb_CType_String: - return sizeof(upb_StringView); + if (ctx->layout) { + UPB_ASSERT(upb_FieldDef_Number(f) == ext->field.number); + } else { + upb_StringView desc; + if (!upb_FieldDef_MiniDescriptorEncode(f, ctx->tmp_arena, &desc)) { + _upb_DefBuilder_OomErr(ctx); + } + + upb_MiniTable_Extension* mut_ext = (upb_MiniTable_Extension*)ext; + upb_MiniTable_Sub sub; + sub.submsg = NULL; + sub.subenum = NULL; + bool ok2 = upb_MiniTable_BuildExtension(desc.data, desc.size, mut_ext, + upb_MessageDef_MiniTable(m), sub, + ctx->status); + if (!ok2) _upb_DefBuilder_Errf(ctx, "Could not build extension mini table"); + + assert(mut_ext->field.number == f->number_); + mut_ext->extendee = upb_MessageDef_MiniTable(m); + if (upb_FieldDef_IsSubMessage(f)) { + mut_ext->sub.submsg = upb_MessageDef_MiniTable(f->sub.msgdef); + } else if (mut_ext->field.descriptortype == kUpb_FieldType_Enum) { + mut_ext->sub.subenum = _upb_EnumDef_MiniTable(f->sub.enumdef); + } } - UPB_UNREACHABLE(); + + bool ok = _upb_DefPool_InsertExt(ctx->symtab, ext, f); + if (!ok) _upb_DefBuilder_OomErr(ctx); } -static uint8_t upb_msg_fielddefsize(const upb_FieldDef* f) { - if (upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f))) { - upb_MapEntry ent; - UPB_ASSERT(sizeof(ent.k) == sizeof(ent.v)); - return sizeof(ent.k); - } else if (upb_FieldDef_IsRepeated(f)) { - return sizeof(void*); +static void resolve_default(upb_DefBuilder* ctx, upb_FieldDef* f, + const google_protobuf_FieldDescriptorProto* field_proto) { + // Have to delay resolving of the default value until now because of the enum + // case, since enum defaults are specified with a label. + if (google_protobuf_FieldDescriptorProto_has_default_value(field_proto)) { + upb_StringView defaultval = + google_protobuf_FieldDescriptorProto_default_value(field_proto); + + if (upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3) { + _upb_DefBuilder_Errf(ctx, + "proto3 fields cannot have explicit defaults (%s)", + f->full_name); + } + + if (upb_FieldDef_IsSubMessage(f)) { + _upb_DefBuilder_Errf(ctx, + "message fields cannot have explicit defaults (%s)", + f->full_name); + } + + parse_default(ctx, defaultval.data, defaultval.size, f); + f->has_default = true; } else { - return upb_MessageValue_sizeof(upb_FieldDef_CType(f)); + set_default_default(ctx, f); + f->has_default = false; } } -static uint32_t upb_MiniTable_place(symtab_addctx* ctx, upb_MiniTable* l, - size_t size, const upb_MessageDef* m) { - size_t ofs = UPB_ALIGN_UP(l->size, size); - size_t next = ofs + size; - - if (next > UINT16_MAX) { - symtab_errf(ctx, "size of message %s exceeded max size of %zu bytes", - upb_MessageDef_FullName(m), (size_t)UINT16_MAX); - } - - l->size = next; - return ofs; -} +void _upb_FieldDef_Resolve(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f) { + // We have to stash this away since resolve_subdef() may overwrite it. + const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; -static int field_number_cmp(const void* p1, const void* p2) { - const upb_MiniTable_Field* f1 = p1; - const upb_MiniTable_Field* f2 = p2; - return f1->number - f2->number; -} + resolve_subdef(ctx, prefix, f); + resolve_default(ctx, f, field_proto); -static void assign_layout_indices(const upb_MessageDef* m, upb_MiniTable* l, - upb_MiniTable_Field* fields) { - int i; - int n = upb_MessageDef_numfields(m); - int dense_below = 0; - for (i = 0; i < n; i++) { - upb_FieldDef* f = - (upb_FieldDef*)upb_MessageDef_FindFieldByNumber(m, fields[i].number); - UPB_ASSERT(f); - f->layout_index = i; - if (i < UINT8_MAX && fields[i].number == i + 1 && - (i == 0 || fields[i - 1].number == i)) { - dense_below = i + 1; - } + if (f->is_extension_) { + resolve_extension(ctx, prefix, f, field_proto); } - l->dense_below = dense_below; } -static uint8_t map_descriptortype(const upb_FieldDef* f) { - uint8_t type = upb_FieldDef_Type(f); - /* See TableDescriptorType() in upbc/generator.cc for details and - * rationale of these exceptions. */ - if (type == kUpb_FieldType_String && f->file->syntax == kUpb_Syntax_Proto2) { - return kUpb_FieldType_Bytes; - } else if (type == kUpb_FieldType_Enum && - (f->sub.enumdef->file->syntax == kUpb_Syntax_Proto3 || - UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 || - // TODO(https://github.com/protocolbuffers/upb/issues/541): - // fix map enum values to check for unknown enum values and put - // them in the unknown field set. - upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f)))) { - return kUpb_FieldType_Int32; - } - return type; -} -static void fill_fieldlayout(upb_MiniTable_Field* field, - const upb_FieldDef* f) { - field->number = upb_FieldDef_Number(f); - field->descriptortype = map_descriptortype(f); - if (upb_FieldDef_IsMap(f)) { - field->mode = - kUpb_FieldMode_Map | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift); - } else if (upb_FieldDef_IsRepeated(f)) { - field->mode = - kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift); - } else { - /* Maps descriptor type -> elem_size_lg2. */ - static const uint8_t sizes[] = { - -1, /* invalid descriptor type */ - kUpb_FieldRep_8Byte, /* DOUBLE */ - kUpb_FieldRep_4Byte, /* FLOAT */ - kUpb_FieldRep_8Byte, /* INT64 */ - kUpb_FieldRep_8Byte, /* UINT64 */ - kUpb_FieldRep_4Byte, /* INT32 */ - kUpb_FieldRep_8Byte, /* FIXED64 */ - kUpb_FieldRep_4Byte, /* FIXED32 */ - kUpb_FieldRep_1Byte, /* BOOL */ - kUpb_FieldRep_StringView, /* STRING */ - kUpb_FieldRep_Pointer, /* GROUP */ - kUpb_FieldRep_Pointer, /* MESSAGE */ - kUpb_FieldRep_StringView, /* BYTES */ - kUpb_FieldRep_4Byte, /* UINT32 */ - kUpb_FieldRep_4Byte, /* ENUM */ - kUpb_FieldRep_4Byte, /* SFIXED32 */ - kUpb_FieldRep_8Byte, /* SFIXED64 */ - kUpb_FieldRep_4Byte, /* SINT32 */ - kUpb_FieldRep_8Byte, /* SINT64 */ - }; - field->mode = kUpb_FieldMode_Scalar | - (sizes[field->descriptortype] << kUpb_FieldRep_Shift); - } - - if (upb_FieldDef_IsPacked(f)) { - field->mode |= kUpb_LabelFlags_IsPacked; - } +// Must be last. - if (upb_FieldDef_IsExtension(f)) { - field->mode |= kUpb_LabelFlags_IsExtension; - } -} +struct upb_FileDef { + const google_protobuf_FileOptions* opts; + const char* name; + const char* package; -/* This function is the dynamic equivalent of message_layout.{cc,h} in upbc. - * It computes a dynamic layout for all of the fields in |m|. */ -static void make_layout(symtab_addctx* ctx, const upb_MessageDef* m) { - upb_MiniTable* l = (upb_MiniTable*)m->layout; - size_t field_count = upb_MessageDef_numfields(m); - size_t sublayout_count = 0; - upb_MiniTable_Sub* subs; - upb_MiniTable_Field* fields; + const upb_FileDef** deps; + const int32_t* public_deps; + const int32_t* weak_deps; + const upb_MessageDef* top_lvl_msgs; + const upb_EnumDef* top_lvl_enums; + const upb_FieldDef* top_lvl_exts; + const upb_ServiceDef* services; + const upb_MiniTable_Extension** ext_layouts; + const upb_DefPool* symtab; - memset(l, 0, sizeof(*l) + sizeof(_upb_FastTable_Entry)); + int dep_count; + int public_dep_count; + int weak_dep_count; + int top_lvl_msg_count; + int top_lvl_enum_count; + int top_lvl_ext_count; + int service_count; + int ext_count; // All exts in the file. + upb_Syntax syntax; +}; - /* Count sub-messages. */ - for (size_t i = 0; i < field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - if (upb_FieldDef_IsSubMessage(f)) { - sublayout_count++; - } - if (upb_FieldDef_CType(f) == kUpb_CType_Enum && - f->sub.enumdef->file->syntax == kUpb_Syntax_Proto2) { - sublayout_count++; - } - } +const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f) { + return f->opts; +} - fields = symtab_alloc(ctx, field_count * sizeof(*fields)); - subs = symtab_alloc(ctx, sublayout_count * sizeof(*subs)); +bool upb_FileDef_HasOptions(const upb_FileDef* f) { + return f->opts != (void*)kUpbDefOptDefault; +} - l->field_count = upb_MessageDef_numfields(m); - l->fields = fields; - l->subs = subs; - l->table_mask = 0; - l->required_count = 0; +const char* upb_FileDef_Name(const upb_FileDef* f) { return f->name; } - if (upb_MessageDef_ExtensionRangeCount(m) > 0) { - if (google_protobuf_MessageOptions_message_set_wire_format(m->opts)) { - l->ext = kUpb_ExtMode_IsMessageSet; - } else { - l->ext = kUpb_ExtMode_Extendable; - } - } else { - l->ext = kUpb_ExtMode_NonExtendable; - } +const char* upb_FileDef_Package(const upb_FileDef* f) { + return f->package ? f->package : ""; +} - /* TODO(haberman): initialize fast tables so that reflection-based parsing - * can get the same speeds as linked-in types. */ - l->fasttable[0].field_parser = &fastdecode_generic; - l->fasttable[0].field_data = 0; +const char* _upb_FileDef_RawPackage(const upb_FileDef* f) { return f->package; } - if (upb_MessageDef_IsMapEntry(m)) { - /* TODO(haberman): refactor this method so this special case is more - * elegant. */ - const upb_FieldDef* key = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_FieldDef* val = upb_MessageDef_FindFieldByNumber(m, 2); - fields[0].number = 1; - fields[1].number = 2; - fields[0].mode = kUpb_FieldMode_Scalar; - fields[1].mode = kUpb_FieldMode_Scalar; - fields[0].presence = 0; - fields[1].presence = 0; - fields[0].descriptortype = map_descriptortype(key); - fields[1].descriptortype = map_descriptortype(val); - fields[0].offset = 0; - fields[1].offset = sizeof(upb_StringView); - fields[1].submsg_index = 0; - - if (upb_FieldDef_CType(val) == kUpb_CType_Message) { - subs[0].submsg = upb_FieldDef_MessageSubDef(val)->layout; - } - - upb_FieldDef* fielddefs = (upb_FieldDef*)&m->fields[0]; - UPB_ASSERT(fielddefs[0].number_ == 1); - UPB_ASSERT(fielddefs[1].number_ == 2); - fielddefs[0].layout_index = 0; - fielddefs[1].layout_index = 1; - - l->field_count = 2; - l->size = 2 * sizeof(upb_StringView); - l->size = UPB_ALIGN_UP(l->size, 8); - l->dense_below = 2; - return; - } +upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f) { return f->syntax; } - /* Allocate data offsets in three stages: - * - * 1. hasbits. - * 2. regular fields. - * 3. oneof fields. - * - * OPT: There is a lot of room for optimization here to minimize the size. - */ +int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f) { + return f->top_lvl_msg_count; +} - /* Assign hasbits for required fields first. */ - size_t hasbit = 0; +int upb_FileDef_DependencyCount(const upb_FileDef* f) { return f->dep_count; } - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)]; - if (upb_FieldDef_Label(f) == kUpb_Label_Required) { - field->presence = ++hasbit; - if (hasbit >= 63) { - symtab_errf(ctx, "Message with >=63 required fields: %s", - upb_MessageDef_FullName(m)); - } - l->required_count++; - } - } +int upb_FileDef_PublicDependencyCount(const upb_FileDef* f) { + return f->public_dep_count; +} - /* Allocate hasbits and set basic field attributes. */ - sublayout_count = 0; - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)]; - - fill_fieldlayout(field, f); - - if (field->descriptortype == kUpb_FieldType_Message || - field->descriptortype == kUpb_FieldType_Group) { - field->submsg_index = sublayout_count++; - subs[field->submsg_index].submsg = upb_FieldDef_MessageSubDef(f)->layout; - } else if (field->descriptortype == kUpb_FieldType_Enum) { - field->submsg_index = sublayout_count++; - subs[field->submsg_index].subenum = upb_FieldDef_EnumSubDef(f)->layout; - UPB_ASSERT(subs[field->submsg_index].subenum); - } - - if (upb_FieldDef_Label(f) == kUpb_Label_Required) { - /* Hasbit was already assigned. */ - } else if (upb_FieldDef_HasPresence(f) && - !upb_FieldDef_RealContainingOneof(f)) { - /* We don't use hasbit 0, so that 0 can indicate "no presence" in the - * table. This wastes one hasbit, but we don't worry about it for now. */ - field->presence = ++hasbit; - } else { - field->presence = 0; - } - } +int upb_FileDef_WeakDependencyCount(const upb_FileDef* f) { + return f->weak_dep_count; +} - /* Account for space used by hasbits. */ - l->size = hasbit ? div_round_up(hasbit + 1, 8) : 0; +const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f) { + return f->public_deps; +} - /* Allocate non-oneof fields. */ - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - size_t field_size = upb_msg_fielddefsize(f); - size_t index = upb_FieldDef_Index(f); +const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f) { + return f->weak_deps; +} - if (upb_FieldDef_RealContainingOneof(f)) { - /* Oneofs are handled separately below. */ - continue; - } +int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f) { + return f->top_lvl_enum_count; +} - fields[index].offset = upb_MiniTable_place(ctx, l, field_size, m); - } +int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f) { + return f->top_lvl_ext_count; +} - /* Allocate oneof fields. Each oneof field consists of a uint32 for the case - * and space for the actual data. */ - for (int i = 0; i < m->oneof_count; i++) { - const upb_OneofDef* o = &m->oneofs[i]; - size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */ - size_t field_size = 0; - uint32_t case_offset; - uint32_t data_offset; +int upb_FileDef_ServiceCount(const upb_FileDef* f) { return f->service_count; } - if (upb_OneofDef_IsSynthetic(o)) continue; +const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->dep_count); + return f->deps[i]; +} - if (o->field_count == 0) { - symtab_errf(ctx, "Oneof must have at least one field (%s)", o->full_name); - } +const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->public_dep_count); + return f->deps[f->public_deps[i]]; +} - /* Calculate field size: the max of all field sizes. */ - for (int j = 0; j < o->field_count; j++) { - const upb_FieldDef* f = o->fields[j]; - field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f)); - } +const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->public_dep_count); + return f->deps[f->weak_deps[i]]; +} - /* Align and allocate case offset. */ - case_offset = upb_MiniTable_place(ctx, l, case_size, m); - data_offset = upb_MiniTable_place(ctx, l, field_size, m); +const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_msg_count); + return _upb_MessageDef_At(f->top_lvl_msgs, i); +} - for (int i = 0; i < o->field_count; i++) { - const upb_FieldDef* f = o->fields[i]; - fields[upb_FieldDef_Index(f)].offset = data_offset; - fields[upb_FieldDef_Index(f)].presence = ~case_offset; - } - } +const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_enum_count); + return _upb_EnumDef_At(f->top_lvl_enums, i); +} - /* Size of the entire structure should be a multiple of its greatest - * alignment. TODO: track overall alignment for real? */ - l->size = UPB_ALIGN_UP(l->size, 8); +const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_ext_count); + return _upb_FieldDef_At(f->top_lvl_exts, i); +} - /* Sort fields by number. */ - if (fields) { - qsort(fields, upb_MessageDef_numfields(m), sizeof(*fields), - field_number_cmp); - } - assign_layout_indices(m, l, fields); +const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->service_count); + return _upb_ServiceDef_At(f->services, i); } -static char* strviewdup(symtab_addctx* ctx, upb_StringView view) { - char* ret = upb_strdup2(view.data, view.size, ctx->arena); - CHK_OOM(ret); - return ret; +const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f) { return f->symtab; } + +const upb_MiniTable_Extension* _upb_FileDef_ExtensionMiniTable( + const upb_FileDef* f, int i) { + return f->ext_layouts[i]; } -static bool streql2(const char* a, size_t n, const char* b) { - return n == strlen(b) && memcmp(a, b, n) == 0; +static char* strviewdup(upb_DefBuilder* ctx, upb_StringView view) { + char* ret = upb_strdup2(view.data, view.size, _upb_DefBuilder_Arena(ctx)); + if (!ret) _upb_DefBuilder_OomErr(ctx); + return ret; } static bool streql_view(upb_StringView view, const char* b) { - return streql2(view.data, view.size, b); + return view.size == strlen(b) && memcmp(view.data, b, view.size) == 0; } -static const char* makefullname(symtab_addctx* ctx, const char* prefix, - upb_StringView name) { - if (prefix) { - /* ret = prefix + '.' + name; */ - size_t n = strlen(prefix); - char* ret = symtab_alloc(ctx, n + name.size + 2); - strcpy(ret, prefix); - ret[n] = '.'; - memcpy(&ret[n + 1], name.data, name.size); - ret[n + 1 + name.size] = '\0'; - return ret; - } else { - return strviewdup(ctx, name); +static int count_exts_in_msg(const google_protobuf_DescriptorProto* msg_proto) { + size_t n; + google_protobuf_DescriptorProto_extension(msg_proto, &n); + int ext_count = n; + + const google_protobuf_DescriptorProto* const* nested_msgs = + google_protobuf_DescriptorProto_nested_type(msg_proto, &n); + for (size_t i = 0; i < n; i++) { + ext_count += count_exts_in_msg(nested_msgs[i]); } + + return ext_count; } -static void finalize_oneofs(symtab_addctx* ctx, upb_MessageDef* m) { - int i; - int synthetic_count = 0; - upb_OneofDef* mutable_oneofs = (upb_OneofDef*)m->oneofs; +// Allocate and initialize one file def, and add it to the context object. +void _upb_FileDef_Create(upb_DefBuilder* ctx, + const google_protobuf_FileDescriptorProto* file_proto) { + upb_FileDef* file = _upb_DefBuilder_Alloc(ctx, sizeof(upb_FileDef)); + ctx->file = file; - for (i = 0; i < m->oneof_count; i++) { - upb_OneofDef* o = &mutable_oneofs[i]; + const google_protobuf_DescriptorProto* const* msgs; + const google_protobuf_EnumDescriptorProto* const* enums; + const google_protobuf_FieldDescriptorProto* const* exts; + const google_protobuf_ServiceDescriptorProto* const* services; + const upb_StringView* strs; + const int32_t* public_deps; + const int32_t* weak_deps; + size_t n; - if (o->synthetic && o->field_count != 1) { - symtab_errf(ctx, "Synthetic oneofs must have one field, not %d: %s", - o->field_count, upb_OneofDef_Name(o)); - } + file->symtab = ctx->symtab; - if (o->synthetic) { - synthetic_count++; - } else if (synthetic_count != 0) { - symtab_errf(ctx, "Synthetic oneofs must be after all other oneofs: %s", - upb_OneofDef_Name(o)); + // Count all extensions in the file, to build a flat array of layouts. + google_protobuf_FileDescriptorProto_extension(file_proto, &n); + int ext_count = n; + msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); + for (int i = 0; i < n; i++) { + ext_count += count_exts_in_msg(msgs[i]); + } + file->ext_count = ext_count; + + if (ctx->layout) { + // We are using the ext layouts that were passed in. + file->ext_layouts = ctx->layout->exts; + if (ctx->layout->ext_count != file->ext_count) { + _upb_DefBuilder_Errf(ctx, + "Extension count did not match layout (%d vs %d)", + ctx->layout->ext_count, file->ext_count); + } + } else { + // We are building ext layouts from scratch. + file->ext_layouts = _upb_DefBuilder_Alloc( + ctx, sizeof(*file->ext_layouts) * file->ext_count); + upb_MiniTable_Extension* ext = + _upb_DefBuilder_Alloc(ctx, sizeof(*ext) * file->ext_count); + for (int i = 0; i < file->ext_count; i++) { + file->ext_layouts[i] = &ext[i]; } + } - o->fields = symtab_alloc(ctx, sizeof(upb_FieldDef*) * o->field_count); - o->field_count = 0; + if (!google_protobuf_FileDescriptorProto_has_name(file_proto)) { + _upb_DefBuilder_Errf(ctx, "File has no name"); } - for (i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - upb_OneofDef* o = (upb_OneofDef*)upb_FieldDef_ContainingOneof(f); - if (o) { - o->fields[o->field_count++] = f; - } + file->name = strviewdup(ctx, google_protobuf_FileDescriptorProto_name(file_proto)); + + upb_StringView package = google_protobuf_FileDescriptorProto_package(file_proto); + if (package.size) { + _upb_DefBuilder_CheckIdentFull(ctx, package); + file->package = strviewdup(ctx, package); + } else { + file->package = NULL; } - m->real_oneof_count = m->oneof_count - synthetic_count; -} + if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) { + upb_StringView syntax = google_protobuf_FileDescriptorProto_syntax(file_proto); -size_t getjsonname(const char* name, char* buf, size_t len) { - size_t src, dst = 0; - bool ucase_next = false; + if (streql_view(syntax, "proto2")) { + file->syntax = kUpb_Syntax_Proto2; + } else if (streql_view(syntax, "proto3")) { + file->syntax = kUpb_Syntax_Proto3; + } else { + _upb_DefBuilder_Errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(syntax)); + } + } else { + file->syntax = kUpb_Syntax_Proto2; + } -#define WRITE(byte) \ - ++dst; \ - if (dst < len) \ - buf[dst - 1] = byte; \ - else if (dst == len) \ - buf[dst - 1] = '\0' + // Read options. + UBP_DEF_SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); - if (!name) { - WRITE('\0'); - return 0; + // Verify dependencies. + strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n); + file->dep_count = n; + file->deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->deps) * n); + + for (size_t i = 0; i < n; i++) { + upb_StringView str = strs[i]; + file->deps[i] = + upb_DefPool_FindFileByNameWithSize(ctx->symtab, str.data, str.size); + if (!file->deps[i]) { + _upb_DefBuilder_Errf(ctx, + "Depends on file '" UPB_STRINGVIEW_FORMAT + "', but it has not been loaded", + UPB_STRINGVIEW_ARGS(str)); + } } - /* Implement the transformation as described in the spec: - * 1. upper case all letters after an underscore. - * 2. remove all underscores. - */ - for (src = 0; name[src]; src++) { - if (name[src] == '_') { - ucase_next = true; - continue; + public_deps = google_protobuf_FileDescriptorProto_public_dependency(file_proto, &n); + file->public_dep_count = n; + file->public_deps = + _upb_DefBuilder_Alloc(ctx, sizeof(*file->public_deps) * n); + int32_t* mutable_public_deps = (int32_t*)file->public_deps; + for (size_t i = 0; i < n; i++) { + if (public_deps[i] >= file->dep_count) { + _upb_DefBuilder_Errf(ctx, "public_dep %d is out of range", + (int)public_deps[i]); } + mutable_public_deps[i] = public_deps[i]; + } - if (ucase_next) { - WRITE(toupper(name[src])); - ucase_next = false; - } else { - WRITE(name[src]); + weak_deps = google_protobuf_FileDescriptorProto_weak_dependency(file_proto, &n); + file->weak_dep_count = n; + file->weak_deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->weak_deps) * n); + int32_t* mutable_weak_deps = (int32_t*)file->weak_deps; + for (size_t i = 0; i < n; i++) { + if (weak_deps[i] >= file->dep_count) { + _upb_DefBuilder_Errf(ctx, "weak_dep %d is out of range", + (int)weak_deps[i]); } + mutable_weak_deps[i] = weak_deps[i]; } - WRITE('\0'); - return dst; + // Create enums. + enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); + file->top_lvl_enum_count = n; + file->top_lvl_enums = _upb_EnumDefs_New(ctx, n, enums, NULL); -#undef WRITE -} + // Create extensions. + exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n); + file->top_lvl_ext_count = n; + file->top_lvl_exts = + _upb_FieldDefs_New(ctx, n, exts, file->package, NULL, NULL); -static char* makejsonname(symtab_addctx* ctx, const char* name) { - size_t size = getjsonname(name, NULL, 0); - char* json_name = symtab_alloc(ctx, size); - getjsonname(name, json_name, size); - return json_name; -} + // Create messages. + msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); + file->top_lvl_msg_count = n; + file->top_lvl_msgs = _upb_MessageDefs_New(ctx, n, msgs, NULL); -/* Adds a symbol |v| to the symtab, which must be a def pointer previously - * packed with pack_def(). The def's pointer to upb_FileDef* must be set before - * adding, so we know which entries to remove if building this file fails. */ -static void symtab_add(symtab_addctx* ctx, const char* name, upb_value v) { - // TODO: table should support an operation "tryinsert" to avoid the double - // lookup. - if (upb_strtable_lookup(&ctx->symtab->syms, name, NULL)) { - symtab_errf(ctx, "duplicate symbol '%s'", name); - } - size_t len = strlen(name); - CHK_OOM(upb_strtable_insert(&ctx->symtab->syms, name, len, v, - ctx->symtab->arena)); -} + // Create services. + services = google_protobuf_FileDescriptorProto_service(file_proto, &n); + file->service_count = n; + file->services = _upb_ServiceDefs_New(ctx, n, services); -static bool remove_component(char* base, size_t* len) { - if (*len == 0) return false; + // Now that all names are in the table, build layouts and resolve refs. - for (size_t i = *len - 1; i > 0; i--) { - if (base[i] == '.') { - *len = i; - return true; - } + for (int i = 0; i < file->top_lvl_msg_count; i++) { + upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); + _upb_MessageDef_Resolve(ctx, m); } - *len = 0; - return true; -} + for (int i = 0; i < file->top_lvl_ext_count; i++) { + upb_FieldDef* f = (upb_FieldDef*)upb_FileDef_TopLevelExtension(file, i); + _upb_FieldDef_Resolve(ctx, file->package, f); + } -/* Given a symbol and the base symbol inside which it is defined, find the - * symbol's definition in t. */ -static const void* symtab_resolveany(symtab_addctx* ctx, - const char* from_name_dbg, - const char* base, upb_StringView sym, - upb_deftype_t* type) { - const upb_strtable* t = &ctx->symtab->syms; - if (sym.size == 0) goto notfound; - upb_value v; - if (sym.data[0] == '.') { - /* Symbols starting with '.' are absolute, so we do a single lookup. - * Slice to omit the leading '.' */ - if (!upb_strtable_lookup2(t, sym.data + 1, sym.size - 1, &v)) { - goto notfound; - } - } else { - /* Remove components from base until we find an entry or run out. */ - size_t baselen = base ? strlen(base) : 0; - char* tmp = malloc(sym.size + baselen + 1); - while (1) { - char* p = tmp; - if (baselen) { - memcpy(p, base, baselen); - p[baselen] = '.'; - p += baselen + 1; - } - memcpy(p, sym.data, sym.size); - p += sym.size; - if (upb_strtable_lookup2(t, tmp, p - tmp, &v)) { - break; - } - if (!remove_component(tmp, &baselen)) { - free(tmp); - goto notfound; - } + if (!ctx->layout) { + for (int i = 0; i < file->top_lvl_msg_count; i++) { + upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); + _upb_MessageDef_LinkMiniTable(ctx, m); } - free(tmp); } - *type = deftype(v); - return unpack_def(v, *type); - -notfound: - symtab_errf(ctx, "couldn't resolve name '" UPB_STRINGVIEW_FORMAT "'", - UPB_STRINGVIEW_ARGS(sym)); -} - -static const void* symtab_resolve(symtab_addctx* ctx, const char* from_name_dbg, - const char* base, upb_StringView sym, - upb_deftype_t type) { - upb_deftype_t found_type; - const void* ret = - symtab_resolveany(ctx, from_name_dbg, base, sym, &found_type); - if (ret && found_type != type) { - symtab_errf(ctx, - "type mismatch when resolving %s: couldn't find " - "name " UPB_STRINGVIEW_FORMAT " with type=%d", - from_name_dbg, UPB_STRINGVIEW_ARGS(sym), (int)type); + if (file->ext_count) { + bool ok = _upb_extreg_add(_upb_DefPool_ExtReg(ctx->symtab), + file->ext_layouts, file->ext_count); + if (!ok) _upb_DefBuilder_OomErr(ctx); } - return ret; } -static void create_oneofdef( - symtab_addctx* ctx, upb_MessageDef* m, - const google_protobuf_OneofDescriptorProto* oneof_proto, - const upb_OneofDef* _o) { - upb_OneofDef* o = (upb_OneofDef*)_o; - upb_StringView name = google_protobuf_OneofDescriptorProto_name(oneof_proto); - upb_value v; - - o->parent = m; - o->full_name = makefullname(ctx, m->full_name, name); - o->field_count = 0; - o->synthetic = false; - SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); +#include - upb_value existing_v; - if (upb_strtable_lookup2(&m->ntof, name.data, name.size, &existing_v)) { - symtab_errf(ctx, "duplicate oneof name (%s)", o->full_name); - } - v = pack_def(o, UPB_DEFTYPE_ONEOF); - CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, v, ctx->arena)); +// Must be last. - CHK_OOM(upb_inttable_init(&o->itof, ctx->arena)); - CHK_OOM(upb_strtable_init(&o->ntof, 4, ctx->arena)); +static size_t get_field_size(const upb_MiniTable_Field* f) { + static unsigned char sizes[] = { + 0, /* 0 */ + 8, /* kUpb_FieldType_Double */ + 4, /* kUpb_FieldType_Float */ + 8, /* kUpb_FieldType_Int64 */ + 8, /* kUpb_FieldType_UInt64 */ + 4, /* kUpb_FieldType_Int32 */ + 8, /* kUpb_FieldType_Fixed64 */ + 4, /* kUpb_FieldType_Fixed32 */ + 1, /* kUpb_FieldType_Bool */ + sizeof(upb_StringView), /* kUpb_FieldType_String */ + sizeof(void*), /* kUpb_FieldType_Group */ + sizeof(void*), /* kUpb_FieldType_Message */ + sizeof(upb_StringView), /* kUpb_FieldType_Bytes */ + 4, /* kUpb_FieldType_UInt32 */ + 4, /* kUpb_FieldType_Enum */ + 4, /* kUpb_FieldType_SFixed32 */ + 8, /* kUpb_FieldType_SFixed64 */ + 4, /* kUpb_FieldType_SInt32 */ + 8, /* kUpb_FieldType_SInt64 */ + }; + return upb_IsRepeatedOrMap(f) ? sizeof(void*) : sizes[f->descriptortype]; } -static str_t* newstr(symtab_addctx* ctx, const char* data, size_t len) { - str_t* ret = symtab_alloc(ctx, sizeof(*ret) + len); - CHK_OOM(ret); - ret->len = len; - if (len) memcpy(ret->str, data, len); - ret->str[len] = '\0'; - return ret; +upb_Message* upb_Message_New(const upb_MessageDef* m, upb_Arena* a) { + return _upb_Message_New(upb_MessageDef_MiniTable(m), a); } -static bool upb_DefPool_TryGetChar(const char** src, const char* end, - char* ch) { - if (*src == end) return false; - *ch = **src; - *src += 1; - return true; +static bool in_oneof(const upb_MiniTable_Field* field) { + return field->presence < 0; } -static char upb_DefPool_TryGetHexDigit(symtab_addctx* ctx, - const upb_FieldDef* f, const char** src, - const char* end) { - char ch; - if (!upb_DefPool_TryGetChar(src, end, &ch)) return -1; - if ('0' <= ch && ch <= '9') { - return ch - '0'; - } - ch = upb_ascii_lower(ch); - if ('a' <= ch && ch <= 'f') { - return ch - 'a' + 0xa; - } - *src -= 1; // Char wasn't actually a hex digit. - return -1; +static upb_MessageValue _upb_Message_Getraw(const upb_Message* msg, + const upb_FieldDef* f) { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); + const char* mem = UPB_PTR_AT(msg, field->offset, char); + upb_MessageValue val = {0}; + memcpy(&val, mem, get_field_size(field)); + return val; } -static char upb_DefPool_ParseHexEscape(symtab_addctx* ctx, - const upb_FieldDef* f, const char** src, - const char* end) { - char hex_digit = upb_DefPool_TryGetHexDigit(ctx, f, src, end); - if (hex_digit < 0) { - symtab_errf(ctx, - "\\x cannot be followed by non-hex digit in field '%s' default", - upb_FieldDef_FullName(f)); - return 0; - } - unsigned int ret = hex_digit; - while ((hex_digit = upb_DefPool_TryGetHexDigit(ctx, f, src, end)) >= 0) { - ret = (ret << 4) | hex_digit; - } - if (ret > 0xff) { - symtab_errf(ctx, "Value of hex escape in field %s exceeds 8 bits", - upb_FieldDef_FullName(f)); - return 0; +bool upb_Message_Has(const upb_Message* msg, const upb_FieldDef* f) { + assert(upb_FieldDef_HasPresence(f)); + if (upb_FieldDef_IsExtension(f)) { + const upb_MiniTable_Extension* ext = _upb_FieldDef_ExtensionMiniTable(f); + return _upb_Message_Getext(msg, ext) != NULL; + } else { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); + if (in_oneof(field)) { + return _upb_getoneofcase_field(msg, field) == field->number; + } else if (field->presence > 0) { + return _upb_hasbit_field(msg, field); + } else { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message || + field->descriptortype == kUpb_FieldType_Group); + return _upb_Message_Getraw(msg, f).msg_val != NULL; + } } - return ret; } -char upb_DefPool_TryGetOctalDigit(const char** src, const char* end) { - char ch; - if (!upb_DefPool_TryGetChar(src, end, &ch)) return -1; - if ('0' <= ch && ch <= '7') { - return ch - '0'; +const upb_FieldDef* upb_Message_WhichOneof(const upb_Message* msg, + const upb_OneofDef* o) { + const upb_FieldDef* f = upb_OneofDef_Field(o, 0); + if (upb_OneofDef_IsSynthetic(o)) { + UPB_ASSERT(upb_OneofDef_FieldCount(o) == 1); + return upb_Message_Has(msg, f) ? f : NULL; + } else { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); + uint32_t oneof_case = _upb_getoneofcase_field(msg, field); + f = oneof_case ? upb_OneofDef_LookupNumber(o, oneof_case) : NULL; + UPB_ASSERT((f != NULL) == (oneof_case != 0)); + return f; } - *src -= 1; // Char wasn't actually an octal digit. - return -1; } -static char upb_DefPool_ParseOctalEscape(symtab_addctx* ctx, - const upb_FieldDef* f, - const char** src, const char* end) { - char ch = 0; - for (int i = 0; i < 3; i++) { - char digit; - if ((digit = upb_DefPool_TryGetOctalDigit(src, end)) >= 0) { - ch = (ch << 3) | digit; +upb_MessageValue upb_Message_Get(const upb_Message* msg, + const upb_FieldDef* f) { + if (upb_FieldDef_IsExtension(f)) { + const upb_Message_Extension* ext = + _upb_Message_Getext(msg, _upb_FieldDef_ExtensionMiniTable(f)); + if (ext) { + upb_MessageValue val; + memcpy(&val, &ext->data, sizeof(val)); + return val; + } else if (upb_FieldDef_IsRepeated(f)) { + return (upb_MessageValue){.array_val = NULL}; } + } else if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) { + return _upb_Message_Getraw(msg, f); } - return ch; + return upb_FieldDef_Default(f); } -static char upb_DefPool_ParseEscape(symtab_addctx* ctx, const upb_FieldDef* f, - const char** src, const char* end) { - char ch; - if (!upb_DefPool_TryGetChar(src, end, &ch)) { - symtab_errf(ctx, "unterminated escape sequence in field %s", - upb_FieldDef_FullName(f)); - return 0; +upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, + const upb_FieldDef* f, + upb_Arena* a) { + UPB_ASSERT(upb_FieldDef_IsSubMessage(f) || upb_FieldDef_IsRepeated(f)); + if (upb_FieldDef_HasPresence(f) && !upb_Message_Has(msg, f)) { + // We need to skip the upb_Message_Get() call in this case. + goto make; } - switch (ch) { - case 'a': - return '\a'; - case 'b': - return '\b'; - case 'f': - return '\f'; - case 'n': - return '\n'; - case 'r': - return '\r'; - case 't': - return '\t'; - case 'v': - return '\v'; - case '\\': - return '\\'; - case '\'': - return '\''; - case '\"': - return '\"'; - case '?': - return '\?'; - case 'x': - case 'X': - return upb_DefPool_ParseHexEscape(ctx, f, src, end); - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - *src -= 1; - return upb_DefPool_ParseOctalEscape(ctx, f, src, end); + + upb_MessageValue val = upb_Message_Get(msg, f); + if (val.array_val) { + return (upb_MutableMessageValue){.array = (upb_Array*)val.array_val}; + } + + upb_MutableMessageValue ret; +make: + if (!a) return (upb_MutableMessageValue){.array = NULL}; + if (upb_FieldDef_IsMap(f)) { + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key = + upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_KeyFieldNumber); + const upb_FieldDef* value = + upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_ValueFieldNumber); + ret.map = + upb_Map_New(a, upb_FieldDef_CType(key), upb_FieldDef_CType(value)); + } else if (upb_FieldDef_IsRepeated(f)) { + ret.array = upb_Array_New(a, upb_FieldDef_CType(f)); + } else { + UPB_ASSERT(upb_FieldDef_IsSubMessage(f)); + ret.msg = upb_Message_New(upb_FieldDef_MessageSubDef(f), a); + } + + val.array_val = ret.array; + upb_Message_Set(msg, f, val, a); + + return ret; +} + +bool upb_Message_Set(upb_Message* msg, const upb_FieldDef* f, + upb_MessageValue val, upb_Arena* a) { + if (upb_FieldDef_IsExtension(f)) { + upb_Message_Extension* ext = _upb_Message_GetOrCreateExtension( + msg, _upb_FieldDef_ExtensionMiniTable(f), a); + if (!ext) return false; + memcpy(&ext->data, &val, sizeof(val)); + } else { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); + + // Building reflection should always cause all sub-message types to be + // linked, but double-check here just for extra assurance. + UPB_ASSERT(!upb_FieldDef_IsSubMessage(f) || + upb_MessageDef_MiniTable(upb_FieldDef_ContainingType(f)) + ->subs[field->submsg_index] + .submsg); + + char* mem = UPB_PTR_AT(msg, field->offset, char); + memcpy(mem, &val, get_field_size(field)); + if (field->presence > 0) { + _upb_sethas_field(msg, field); + } else if (in_oneof(field)) { + *_upb_oneofcase_field(msg, field) = field->number; + } } - symtab_errf(ctx, "Unknown escape sequence: \\%c", ch); + return true; } -static str_t* unescape(symtab_addctx* ctx, const upb_FieldDef* f, - const char* data, size_t len) { - // Size here is an upper bound; escape sequences could ultimately shrink it. - str_t* ret = symtab_alloc(ctx, sizeof(*ret) + len); - char* dst = &ret->str[0]; - const char* src = data; - const char* end = data + len; +void upb_Message_ClearField(upb_Message* msg, const upb_FieldDef* f) { + if (upb_FieldDef_IsExtension(f)) { + _upb_Message_Clearext(msg, _upb_FieldDef_ExtensionMiniTable(f)); + } else { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); + char* mem = UPB_PTR_AT(msg, field->offset, char); - while (src < end) { - if (*src == '\\') { - src++; - *dst++ = upb_DefPool_ParseEscape(ctx, f, &src, end); - } else { - *dst++ = *src++; + if (field->presence > 0) { + _upb_clearhas_field(msg, field); + } else if (in_oneof(field)) { + uint32_t* oneof_case = _upb_oneofcase_field(msg, field); + if (*oneof_case != field->number) return; + *oneof_case = 0; } + + memset(mem, 0, get_field_size(field)); } +} - ret->len = dst - &ret->str[0]; - return ret; +void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m) { + _upb_Message_Clear(msg, upb_MessageDef_MiniTable(m)); } -static void parse_default(symtab_addctx* ctx, const char* str, size_t len, - upb_FieldDef* f) { - char* end; - char nullz[64]; - errno = 0; +bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, const upb_FieldDef** out_f, + upb_MessageValue* out_val, size_t* iter) { + size_t i = *iter; + size_t n = upb_MessageDef_FieldCount(m); + const upb_MessageValue zero = {0}; + UPB_UNUSED(ext_pool); - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Int32: - case kUpb_CType_Int64: - case kUpb_CType_UInt32: - case kUpb_CType_UInt64: - case kUpb_CType_Double: - case kUpb_CType_Float: - /* Standard C number parsing functions expect null-terminated strings. */ - if (len >= sizeof(nullz) - 1) { - symtab_errf(ctx, "Default too long: %.*s", (int)len, str); - } - memcpy(nullz, str, len); - nullz[len] = '\0'; - str = nullz; - break; - default: - break; - } + /* Iterate over normal fields, returning the first one that is set. */ + while (++i < n) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + upb_MessageValue val = _upb_Message_Getraw(msg, f); - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Int32: { - long val = strtol(str, &end, 0); - if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.sint = val; - break; - } - case kUpb_CType_Enum: { - const upb_EnumDef* e = f->sub.enumdef; - const upb_EnumValueDef* ev = - upb_EnumDef_FindValueByNameWithSize(e, str, len); - if (!ev) { - goto invalid; + /* Skip field if unset or empty. */ + if (upb_FieldDef_HasPresence(f)) { + if (!upb_Message_Has(msg, f)) continue; + } else { + upb_MessageValue test = val; + if (upb_FieldDef_IsString(f) && !upb_FieldDef_IsRepeated(f)) { + /* Clear string pointer, only size matters (ptr could be non-NULL). */ + test.str_val.data = NULL; } - f->defaultval.sint = ev->number; - break; - } - case kUpb_CType_Int64: { - long long val = strtoll(str, &end, 0); - if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) { - goto invalid; + /* Continue if NULL or 0. */ + if (memcmp(&test, &zero, sizeof(test)) == 0) continue; + + /* Continue on empty array or map. */ + if (upb_FieldDef_IsMap(f)) { + if (upb_Map_Size(test.map_val) == 0) continue; + } else if (upb_FieldDef_IsRepeated(f)) { + if (upb_Array_Size(test.array_val) == 0) continue; } - f->defaultval.sint = val; - break; } - case kUpb_CType_UInt32: { - unsigned long val = strtoul(str, &end, 0); - if (val > UINT32_MAX || errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.uint = val; - break; + + *out_val = val; + *out_f = f; + *iter = i; + return true; + } + + if (ext_pool) { + /* Return any extensions that are set. */ + size_t count; + const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &count); + if (i - n < count) { + ext += count - 1 - (i - n); + memcpy(out_val, &ext->data, sizeof(*out_val)); + *out_f = _upb_DefPool_FindExtensionByMiniTable(ext_pool, ext->ext); + *iter = i; + return true; } - case kUpb_CType_UInt64: { - unsigned long long val = strtoull(str, &end, 0); - if (val > UINT64_MAX || errno == ERANGE || *end) { - goto invalid; + } + + *iter = i; + return false; +} + +bool _upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, + int depth) { + size_t iter = kUpb_Message_Begin; + const upb_FieldDef* f; + upb_MessageValue val; + bool ret = true; + + if (--depth == 0) return false; + + _upb_Message_DiscardUnknown_shallow(msg); + + while (upb_Message_Next(msg, m, NULL /*ext_pool*/, &f, &val, &iter)) { + const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); + if (!subm) continue; + if (upb_FieldDef_IsMap(f)) { + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(subm, 2); + const upb_MessageDef* val_m = upb_FieldDef_MessageSubDef(val_f); + upb_Map* map = (upb_Map*)val.map_val; + size_t iter = kUpb_Map_Begin; + + if (!val_m) continue; + + while (upb_MapIterator_Next(map, &iter)) { + upb_MessageValue map_val = upb_MapIterator_Value(map, iter); + if (!_upb_Message_DiscardUnknown((upb_Message*)map_val.msg_val, val_m, + depth)) { + ret = false; + } } - f->defaultval.uint = val; - break; - } - case kUpb_CType_Double: { - double val = strtod(str, &end); - if (errno == ERANGE || *end) { - goto invalid; + } else if (upb_FieldDef_IsRepeated(f)) { + const upb_Array* arr = val.array_val; + size_t i, n = upb_Array_Size(arr); + for (i = 0; i < n; i++) { + upb_MessageValue elem = upb_Array_Get(arr, i); + if (!_upb_Message_DiscardUnknown((upb_Message*)elem.msg_val, subm, + depth)) { + ret = false; + } } - f->defaultval.dbl = val; - break; - } - case kUpb_CType_Float: { - float val = strtof(str, &end); - if (errno == ERANGE || *end) { - goto invalid; + } else { + if (!_upb_Message_DiscardUnknown((upb_Message*)val.msg_val, subm, + depth)) { + ret = false; } - f->defaultval.flt = val; - break; } - case kUpb_CType_Bool: { - if (streql2(str, len, "false")) { - f->defaultval.boolean = false; - } else if (streql2(str, len, "true")) { - f->defaultval.boolean = true; - } else { - goto invalid; - } - break; + } + + return ret; +} + +bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, + int maxdepth) { + return _upb_Message_DiscardUnknown(msg, m, maxdepth); +} + + + +// Must be last. + +struct upb_MessageDef { + const google_protobuf_MessageOptions* opts; + const upb_MiniTable* layout; + const upb_FileDef* file; + const upb_MessageDef* containing_type; + const char* full_name; + + // Tables for looking up fields by number and name. + upb_inttable itof; + upb_strtable ntof; + + /* All nested defs. + * MEM: We could save some space here by putting nested defs in a contiguous + * region and calculating counts from offsets or vice-versa. */ + const upb_FieldDef* fields; + const upb_OneofDef* oneofs; + const upb_ExtensionRange* ext_ranges; + const upb_MessageDef* nested_msgs; + const upb_EnumDef* nested_enums; + const upb_FieldDef* nested_exts; + int field_count; + int real_oneof_count; + int oneof_count; + int ext_range_count; + int nested_msg_count; + int nested_enum_count; + int nested_ext_count; + bool in_message_set; + bool is_sorted; + upb_WellKnown well_known_type; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif +}; + +static void assign_msg_wellknowntype(upb_MessageDef* m) { + const char* name = upb_MessageDef_FullName(m); + if (name == NULL) { + m->well_known_type = kUpb_WellKnown_Unspecified; + return; + } + if (!strcmp(name, "google.protobuf.Any")) { + m->well_known_type = kUpb_WellKnown_Any; + } else if (!strcmp(name, "google.protobuf.FieldMask")) { + m->well_known_type = kUpb_WellKnown_FieldMask; + } else if (!strcmp(name, "google.protobuf.Duration")) { + m->well_known_type = kUpb_WellKnown_Duration; + } else if (!strcmp(name, "google.protobuf.Timestamp")) { + m->well_known_type = kUpb_WellKnown_Timestamp; + } else if (!strcmp(name, "google.protobuf.DoubleValue")) { + m->well_known_type = kUpb_WellKnown_DoubleValue; + } else if (!strcmp(name, "google.protobuf.FloatValue")) { + m->well_known_type = kUpb_WellKnown_FloatValue; + } else if (!strcmp(name, "google.protobuf.Int64Value")) { + m->well_known_type = kUpb_WellKnown_Int64Value; + } else if (!strcmp(name, "google.protobuf.UInt64Value")) { + m->well_known_type = kUpb_WellKnown_UInt64Value; + } else if (!strcmp(name, "google.protobuf.Int32Value")) { + m->well_known_type = kUpb_WellKnown_Int32Value; + } else if (!strcmp(name, "google.protobuf.UInt32Value")) { + m->well_known_type = kUpb_WellKnown_UInt32Value; + } else if (!strcmp(name, "google.protobuf.BoolValue")) { + m->well_known_type = kUpb_WellKnown_BoolValue; + } else if (!strcmp(name, "google.protobuf.StringValue")) { + m->well_known_type = kUpb_WellKnown_StringValue; + } else if (!strcmp(name, "google.protobuf.BytesValue")) { + m->well_known_type = kUpb_WellKnown_BytesValue; + } else if (!strcmp(name, "google.protobuf.Value")) { + m->well_known_type = kUpb_WellKnown_Value; + } else if (!strcmp(name, "google.protobuf.ListValue")) { + m->well_known_type = kUpb_WellKnown_ListValue; + } else if (!strcmp(name, "google.protobuf.Struct")) { + m->well_known_type = kUpb_WellKnown_Struct; + } else { + m->well_known_type = kUpb_WellKnown_Unspecified; + } +} + +upb_MessageDef* _upb_MessageDef_At(const upb_MessageDef* m, int i) { + return (upb_MessageDef*)&m[i]; +} + +bool _upb_MessageDef_IsValidExtensionNumber(const upb_MessageDef* m, int n) { + for (int i = 0; i < m->ext_range_count; i++) { + const upb_ExtensionRange* r = upb_MessageDef_ExtensionRange(m, i); + if (upb_ExtensionRange_Start(r) <= n && n < upb_ExtensionRange_End(r)) { + return true; } - case kUpb_CType_String: - f->defaultval.str = newstr(ctx, str, len); - break; - case kUpb_CType_Bytes: - f->defaultval.str = unescape(ctx, f, str, len); - break; - case kUpb_CType_Message: - /* Should not have a default value. */ - symtab_errf(ctx, "Message should not have a default (%s)", - upb_FieldDef_FullName(f)); } + return false; +} - return; +const google_protobuf_MessageOptions* upb_MessageDef_Options( + const upb_MessageDef* m) { + return m->opts; +} -invalid: - symtab_errf(ctx, "Invalid default '%.*s' for field %s of type %d", (int)len, - str, upb_FieldDef_FullName(f), (int)upb_FieldDef_Type(f)); +bool upb_MessageDef_HasOptions(const upb_MessageDef* m) { + return m->opts != (void*)kUpbDefOptDefault; } -static void set_default_default(symtab_addctx* ctx, upb_FieldDef* f) { - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Int32: - case kUpb_CType_Int64: - f->defaultval.sint = 0; - break; - case kUpb_CType_UInt64: - case kUpb_CType_UInt32: - f->defaultval.uint = 0; - break; - case kUpb_CType_Double: - case kUpb_CType_Float: - f->defaultval.dbl = 0; - break; - case kUpb_CType_String: - case kUpb_CType_Bytes: - f->defaultval.str = newstr(ctx, NULL, 0); - break; - case kUpb_CType_Bool: - f->defaultval.boolean = false; - break; - case kUpb_CType_Enum: - f->defaultval.sint = f->sub.enumdef->values[0].number; - case kUpb_CType_Message: - break; - } +const char* upb_MessageDef_FullName(const upb_MessageDef* m) { + return m->full_name; } -static void create_fielddef( - symtab_addctx* ctx, const char* prefix, upb_MessageDef* m, - const google_protobuf_FieldDescriptorProto* field_proto, - const upb_FieldDef* _f, bool is_extension) { - upb_FieldDef* f = (upb_FieldDef*)_f; - upb_StringView name; - const char* full_name; - const char* json_name; - const char* shortname; - int32_t field_number; +const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m) { + return m->file; +} + +const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m) { + return m->containing_type; +} - f->file = ctx->file; /* Must happen prior to symtab_add(). */ +const char* upb_MessageDef_Name(const upb_MessageDef* m) { + return _upb_DefBuilder_FullToShort(m->full_name); +} - if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { - symtab_errf(ctx, "field has no name"); +upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m) { + return upb_FileDef_Syntax(m->file); +} + +const upb_FieldDef* upb_MessageDef_FindFieldByNumber(const upb_MessageDef* m, + uint32_t i) { + upb_value val; + return upb_inttable_lookup(&m->itof, i, &val) ? upb_value_getconstptr(val) + : NULL; +} + +const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; + + if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; } - name = google_protobuf_FieldDescriptorProto_name(field_proto); - check_ident(ctx, name, false); - full_name = makefullname(ctx, prefix, name); - shortname = shortdefname(full_name); + return _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); +} - if (google_protobuf_FieldDescriptorProto_has_json_name(field_proto)) { - json_name = strviewdup( - ctx, google_protobuf_FieldDescriptorProto_json_name(field_proto)); - f->has_json_name_ = true; - } else { - json_name = makejsonname(ctx, shortname); - f->has_json_name_ = false; +const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; + + if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; } - field_number = google_protobuf_FieldDescriptorProto_number(field_proto); + return _upb_DefType_Unpack(val, UPB_DEFTYPE_ONEOF); +} - f->full_name = full_name; - f->json_name = json_name; - f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto); - f->number_ = field_number; - f->scope.oneof = NULL; - f->proto3_optional_ = - google_protobuf_FieldDescriptorProto_proto3_optional(field_proto); +bool _upb_MessageDef_Insert(upb_MessageDef* m, const char* name, size_t len, + upb_value v, upb_Arena* a) { + return upb_strtable_insert(&m->ntof, name, len, v, a); +} - bool has_type = google_protobuf_FieldDescriptorProto_has_type(field_proto); - bool has_type_name = - google_protobuf_FieldDescriptorProto_has_type_name(field_proto); +bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, + const char* name, size_t len, + const upb_FieldDef** out_f, + const upb_OneofDef** out_o) { + upb_value val; - f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto); + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return false; + } - if (has_type) { - switch (f->type_) { - case kUpb_FieldType_Message: - case kUpb_FieldType_Group: - case kUpb_FieldType_Enum: - if (!has_type_name) { - symtab_errf(ctx, "field of type %d requires type name (%s)", - (int)f->type_, full_name); - } - break; - default: - if (has_type_name) { - symtab_errf(ctx, "invalid type for field with type_name set (%s, %d)", - full_name, (int)f->type_); - } - } - } else if (has_type_name) { - f->type_ = - FIELD_TYPE_UNSPECIFIED; // We'll fill this in in resolve_fielddef(). + const upb_FieldDef* f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); + const upb_OneofDef* o = _upb_DefType_Unpack(val, UPB_DEFTYPE_ONEOF); + if (out_f) *out_f = f; + if (out_o) *out_o = o; + return f || o; /* False if this was a JSON name. */ +} + +const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; + const upb_FieldDef* f; + + if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; } - if (!is_extension) { - /* direct message field. */ - upb_value v, field_v, json_v, existing_v; - size_t json_size; + f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); + if (!f) f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD_JSONNAME); - if (field_number <= 0 || field_number > kUpb_MaxFieldNumber) { - symtab_errf(ctx, "invalid field number (%u)", field_number); - } + return f; +} - f->index_ = f - m->fields; - f->msgdef = m; - f->is_extension_ = false; +int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) { + return m->ext_range_count; +} - field_v = pack_def(f, UPB_DEFTYPE_FIELD); - json_v = pack_def(f, UPB_DEFTYPE_FIELD_JSONNAME); - v = upb_value_constptr(f); - json_size = strlen(json_name); +int upb_MessageDef_FieldCount(const upb_MessageDef* m) { + return m->field_count; +} - if (upb_strtable_lookup(&m->ntof, shortname, &existing_v)) { - symtab_errf(ctx, "duplicate field name (%s)", shortname); - } +int upb_MessageDef_OneofCount(const upb_MessageDef* m) { + return m->oneof_count; +} - CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, field_v, - ctx->arena)); +int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m) { + return m->nested_msg_count; +} - if (strcmp(shortname, json_name) != 0) { - if (upb_strtable_lookup(&m->ntof, json_name, &v)) { - symtab_errf(ctx, "duplicate json_name (%s)", json_name); - } else { - CHK_OOM(upb_strtable_insert(&m->ntof, json_name, json_size, json_v, - ctx->arena)); - } - } +int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m) { + return m->nested_enum_count; +} - if (upb_inttable_lookup(&m->itof, field_number, NULL)) { - symtab_errf(ctx, "duplicate field number (%u)", field_number); - } +int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m) { + return m->nested_ext_count; +} - CHK_OOM(upb_inttable_insert(&m->itof, field_number, v, ctx->arena)); +const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m) { + return m->layout; +} - if (ctx->layout) { - const upb_MiniTable_Field* fields = m->layout->fields; - int count = m->layout->field_count; - bool found = false; - for (int i = 0; i < count; i++) { - if (fields[i].number == field_number) { - f->layout_index = i; - found = true; - break; - } - } - UPB_ASSERT(found); - } - } else { - /* extension field. */ - f->is_extension_ = true; - f->scope.extension_scope = m; - symtab_add(ctx, full_name, pack_def(f, UPB_DEFTYPE_EXT)); - f->layout_index = ctx->ext_count++; - if (ctx->layout) { - UPB_ASSERT(ctx->file->ext_layouts[f->layout_index]->field.number == - field_number); - } - } +const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->ext_range_count); + return _upb_ExtensionRange_At(m->ext_ranges, i); +} - if (f->type_ < kUpb_FieldType_Double || f->type_ > kUpb_FieldType_SInt64) { - symtab_errf(ctx, "invalid type for field %s (%d)", f->full_name, f->type_); - } +const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->field_count); + return _upb_FieldDef_At(m->fields, i); +} - if (f->label_ < kUpb_Label_Optional || f->label_ > kUpb_Label_Repeated) { - symtab_errf(ctx, "invalid label for field %s (%d)", f->full_name, - f->label_); - } +const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->oneof_count); + return _upb_OneofDef_At(m->oneofs, i); +} - /* We can't resolve the subdef or (in the case of extensions) the containing - * message yet, because it may not have been defined yet. We stash a pointer - * to the field_proto until later when we can properly resolve it. */ - f->sub.unresolved = field_proto; +const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->nested_msg_count); + return &m->nested_msgs[i]; +} - if (f->label_ == kUpb_Label_Required && - f->file->syntax == kUpb_Syntax_Proto3) { - symtab_errf(ctx, "proto3 fields cannot be required (%s)", f->full_name); - } +const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->nested_enum_count); + return _upb_EnumDef_At(m->nested_enums, i); +} - if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { - int oneof_index = - google_protobuf_FieldDescriptorProto_oneof_index(field_proto); - upb_OneofDef* oneof; - upb_value v = upb_value_constptr(f); +const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->nested_ext_count); + return _upb_FieldDef_At(m->nested_exts, i); +} - if (upb_FieldDef_Label(f) != kUpb_Label_Optional) { - symtab_errf(ctx, "fields in oneof must have OPTIONAL label (%s)", - f->full_name); - } +upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m) { + return m->well_known_type; +} - if (!m) { - symtab_errf(ctx, "oneof_index provided for extension field (%s)", - f->full_name); - } +bool _upb_MessageDef_InMessageSet(const upb_MessageDef* m) { + return m->in_message_set; +} - if (oneof_index >= m->oneof_count) { - symtab_errf(ctx, "oneof_index out of range (%s)", f->full_name); - } +const upb_FieldDef* upb_MessageDef_FindFieldByName(const upb_MessageDef* m, + const char* name) { + return upb_MessageDef_FindFieldByNameWithSize(m, name, strlen(name)); +} - oneof = (upb_OneofDef*)&m->oneofs[oneof_index]; - f->scope.oneof = oneof; +const upb_OneofDef* upb_MessageDef_FindOneofByName(const upb_MessageDef* m, + const char* name) { + return upb_MessageDef_FindOneofByNameWithSize(m, name, strlen(name)); +} - oneof->field_count++; - if (f->proto3_optional_) { - oneof->synthetic = true; - } - CHK_OOM(upb_inttable_insert(&oneof->itof, f->number_, v, ctx->arena)); - CHK_OOM( - upb_strtable_insert(&oneof->ntof, name.data, name.size, v, ctx->arena)); - } else { - if (f->proto3_optional_) { - symtab_errf(ctx, "field with proto3_optional was not in a oneof (%s)", - f->full_name); - } - } +bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m) { + return google_protobuf_MessageOptions_map_entry(upb_MessageDef_Options(m)); +} - SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); +bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m) { + return google_protobuf_MessageOptions_message_set_wire_format( + upb_MessageDef_Options(m)); +} - if (google_protobuf_FieldOptions_has_packed(f->opts)) { - f->packed_ = google_protobuf_FieldOptions_packed(f->opts); - } else { - /* Repeated fields default to packed for proto3 only. */ - f->packed_ = upb_FieldDef_IsPrimitive(f) && - f->label_ == kUpb_Label_Repeated && - f->file->syntax == kUpb_Syntax_Proto3; +static upb_MiniTable* _upb_MessageDef_MakeMiniTable(upb_DefBuilder* ctx, + const upb_MessageDef* m) { + if (google_protobuf_MessageOptions_message_set_wire_format(m->opts)) { + return upb_MiniTable_BuildMessageSet(kUpb_MiniTablePlatform_Native, + ctx->arena); } -} -static void create_service( - symtab_addctx* ctx, const google_protobuf_ServiceDescriptorProto* svc_proto, - const upb_ServiceDef* _s) { - upb_ServiceDef* s = (upb_ServiceDef*)_s; - upb_StringView name; - const google_protobuf_MethodDescriptorProto* const* methods; - size_t i, n; + if (upb_MessageDef_IsMapEntry(m)) { + if (m->field_count != 2) { + _upb_DefBuilder_Errf(ctx, "invalid map (%s)", m->full_name); + } - s->file = ctx->file; /* Must happen prior to symtab_add. */ + const upb_FieldDef* f0 = upb_MessageDef_Field(m, 0); + const upb_FieldDef* f1 = upb_MessageDef_Field(m, 1); + const upb_FieldType t0 = upb_FieldDef_Type(f0); + const upb_FieldType t1 = upb_FieldDef_Type(f1); - name = google_protobuf_ServiceDescriptorProto_name(svc_proto); - check_ident(ctx, name, false); - s->full_name = makefullname(ctx, ctx->file->package, name); - symtab_add(ctx, s->full_name, pack_def(s, UPB_DEFTYPE_SERVICE)); + const bool is_proto3_enum = + (t1 == kUpb_FieldType_Enum) && !_upb_FieldDef_IsClosedEnum(f1); + UPB_ASSERT(_upb_FieldDef_LayoutIndex(f0) == 0); + UPB_ASSERT(_upb_FieldDef_LayoutIndex(f1) == 1); - methods = google_protobuf_ServiceDescriptorProto_method(svc_proto, &n); + return upb_MiniTable_BuildMapEntry( + t0, t1, is_proto3_enum, kUpb_MiniTablePlatform_Native, ctx->arena); + } - s->method_count = n; - s->methods = symtab_alloc(ctx, sizeof(*s->methods) * n); + upb_StringView desc; + bool ok = upb_MessageDef_MiniDescriptorEncode(m, ctx->tmp_arena, &desc); + if (!ok) _upb_DefBuilder_OomErr(ctx); - SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, svc_proto); + void** scratch_data = _upb_DefPool_ScratchData(ctx->symtab); + size_t* scratch_size = _upb_DefPool_ScratchSize(ctx->symtab); + upb_MiniTable* ret = upb_MiniTable_BuildWithBuf( + desc.data, desc.size, kUpb_MiniTablePlatform_Native, ctx->arena, + scratch_data, scratch_size, ctx->status); + if (!ret) _upb_DefBuilder_FailJmp(ctx); + return ret; +} - for (i = 0; i < n; i++) { - const google_protobuf_MethodDescriptorProto* method_proto = methods[i]; - upb_MethodDef* m = (upb_MethodDef*)&s->methods[i]; - upb_StringView name = - google_protobuf_MethodDescriptorProto_name(method_proto); - - m->service = s; - m->full_name = makefullname(ctx, s->full_name, name); - m->index = i; - m->client_streaming = - google_protobuf_MethodDescriptorProto_client_streaming(method_proto); - m->server_streaming = - google_protobuf_MethodDescriptorProto_server_streaming(method_proto); - m->input_type = symtab_resolve( - ctx, m->full_name, m->full_name, - google_protobuf_MethodDescriptorProto_input_type(method_proto), - UPB_DEFTYPE_MSG); - m->output_type = symtab_resolve( - ctx, m->full_name, m->full_name, - google_protobuf_MethodDescriptorProto_output_type(method_proto), - UPB_DEFTYPE_MSG); - - SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, method_proto); - } -} - -static int count_bits_debug(uint64_t x) { - // For assertions only, speed does not matter. - int n = 0; - while (x) { - if (x & 1) n++; - x >>= 1; - } - return n; -} - -static int compare_int32(const void* a_ptr, const void* b_ptr) { - int32_t a = *(int32_t*)a_ptr; - int32_t b = *(int32_t*)b_ptr; - return a < b ? -1 : (a == b ? 0 : 1); -} - -upb_MiniTable_Enum* create_enumlayout(symtab_addctx* ctx, - const upb_EnumDef* e) { - int n = 0; - uint64_t mask = 0; - - for (int i = 0; i < e->value_count; i++) { - uint32_t val = (uint32_t)e->values[i].number; - if (val < 64) { - mask |= 1ULL << val; - } else { - n++; - } +void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m) { + for (int i = 0; i < m->field_count; i++) { + upb_FieldDef* f = (upb_FieldDef*)upb_MessageDef_Field(m, i); + _upb_FieldDef_Resolve(ctx, upb_MessageDef_FullName(m), f); } - int32_t* values = symtab_alloc(ctx, sizeof(*values) * n); + if (!ctx->layout) { + m->layout = _upb_MessageDef_MakeMiniTable(ctx, m); + if (!m->layout) _upb_DefBuilder_OomErr(ctx); + } - if (n) { - int32_t* p = values; - - // Add values outside the bitmask range to the list, as described in the - // comments for upb_MiniTable_Enum. - for (int i = 0; i < e->value_count; i++) { - int32_t val = e->values[i].number; - if ((uint32_t)val >= 64) { - *p++ = val; - } + m->in_message_set = false; + for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) { + upb_FieldDef* ext = (upb_FieldDef*)upb_MessageDef_NestedExtension(m, i); + _upb_FieldDef_Resolve(ctx, upb_MessageDef_FullName(m), ext); + if (upb_FieldDef_Type(ext) == kUpb_FieldType_Message && + upb_FieldDef_Label(ext) == kUpb_Label_Optional && + upb_FieldDef_MessageSubDef(ext) == m && + google_protobuf_MessageOptions_message_set_wire_format( + upb_MessageDef_Options(upb_FieldDef_ContainingType(ext)))) { + m->in_message_set = true; } - UPB_ASSERT(p == values + n); } - // Enums can have duplicate values; we must sort+uniq them. - if (values) qsort(values, n, sizeof(*values), &compare_int32); + for (int i = 0; i < upb_MessageDef_NestedMessageCount(m); i++) { + upb_MessageDef* n = (upb_MessageDef*)upb_MessageDef_NestedMessage(m, i); + _upb_MessageDef_Resolve(ctx, n); + } +} + +void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m, + const upb_FieldDef* f) { + const int32_t field_number = upb_FieldDef_Number(f); - int dst = 0; - for (int i = 0; i < n; dst++) { - int32_t val = values[i]; - while (i < n && values[i] == val) i++; // Skip duplicates. - values[dst] = val; + if (field_number <= 0 || field_number > kUpb_MaxFieldNumber) { + _upb_DefBuilder_Errf(ctx, "invalid field number (%u)", field_number); } - n = dst; - UPB_ASSERT(upb_inttable_count(&e->iton) == n + count_bits_debug(mask)); + const char* json_name = upb_FieldDef_JsonName(f); + const char* shortname = upb_FieldDef_Name(f); + const size_t shortnamelen = strlen(shortname); - upb_MiniTable_Enum* layout = symtab_alloc(ctx, sizeof(*layout)); - layout->value_count = n; - layout->mask = mask; - layout->values = values; + upb_value v = upb_value_constptr(f); - return layout; -} + upb_value existing_v; + if (upb_strtable_lookup(&m->ntof, shortname, &existing_v)) { + _upb_DefBuilder_Errf(ctx, "duplicate field name (%s)", shortname); + } -static void create_enumvaldef( - symtab_addctx* ctx, const char* prefix, - const google_protobuf_EnumValueDescriptorProto* val_proto, upb_EnumDef* e, - int i) { - upb_EnumValueDef* val = (upb_EnumValueDef*)&e->values[i]; - upb_StringView name = - google_protobuf_EnumValueDescriptorProto_name(val_proto); - upb_value v = upb_value_constptr(val); + const upb_value field_v = _upb_DefType_Pack(f, UPB_DEFTYPE_FIELD); + bool ok = + _upb_MessageDef_Insert(m, shortname, shortnamelen, field_v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); - val->parent = e; /* Must happen prior to symtab_add(). */ - val->full_name = makefullname(ctx, prefix, name); - val->number = google_protobuf_EnumValueDescriptorProto_number(val_proto); - symtab_add(ctx, val->full_name, pack_def(val, UPB_DEFTYPE_ENUMVAL)); + if (strcmp(shortname, json_name) != 0) { + if (upb_strtable_lookup(&m->ntof, json_name, &v)) { + _upb_DefBuilder_Errf(ctx, "duplicate json_name (%s)", json_name); + } - SET_OPTIONS(val->opts, EnumValueDescriptorProto, EnumValueOptions, val_proto); + const size_t json_size = strlen(json_name); + const upb_value json_v = _upb_DefType_Pack(f, UPB_DEFTYPE_FIELD_JSONNAME); + ok = _upb_MessageDef_Insert(m, json_name, json_size, json_v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + } - if (i == 0 && e->file->syntax == kUpb_Syntax_Proto3 && val->number != 0) { - symtab_errf(ctx, "for proto3, the first enum value must be zero (%s)", - e->full_name); + if (upb_inttable_lookup(&m->itof, field_number, NULL)) { + _upb_DefBuilder_Errf(ctx, "duplicate field number (%u)", field_number); } - CHK_OOM(upb_strtable_insert(&e->ntoi, name.data, name.size, v, ctx->arena)); + ok = upb_inttable_insert(&m->itof, field_number, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} - // Multiple enumerators can have the same number, first one wins. - if (!upb_inttable_lookup(&e->iton, val->number, NULL)) { - CHK_OOM(upb_inttable_insert(&e->iton, val->number, v, ctx->arena)); +void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx, + const upb_MessageDef* m) { + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + const upb_MessageDef* sub_m = upb_FieldDef_MessageSubDef(f); + const upb_EnumDef* sub_e = upb_FieldDef_EnumSubDef(f); + const int layout_index = _upb_FieldDef_LayoutIndex(f); + upb_MiniTable* mt = (upb_MiniTable*)upb_MessageDef_MiniTable(m); + + UPB_ASSERT(layout_index < m->field_count); + upb_MiniTable_Field* mt_f = + (upb_MiniTable_Field*)&m->layout->fields[layout_index]; + if (sub_m) { + if (!mt->subs) { + _upb_DefBuilder_Errf(ctx, "invalid submsg for (%s)", m->full_name); + } + UPB_ASSERT(mt_f); + UPB_ASSERT(sub_m->layout); + upb_MiniTable_SetSubMessage(mt, mt_f, sub_m->layout); + } else if (_upb_FieldDef_IsClosedEnum(f)) { + upb_MiniTable_SetSubEnum(mt, mt_f, _upb_EnumDef_MiniTable(sub_e)); + } } -} -static void create_enumdef( - symtab_addctx* ctx, const char* prefix, - const google_protobuf_EnumDescriptorProto* enum_proto, - const upb_MessageDef* containing_type, const upb_EnumDef* _e) { - upb_EnumDef* e = (upb_EnumDef*)_e; - ; - const google_protobuf_EnumValueDescriptorProto* const* values; - upb_StringView name; - size_t i, n; + for (int i = 0; i < m->nested_msg_count; i++) { + _upb_MessageDef_LinkMiniTable(ctx, upb_MessageDef_NestedMessage(m, i)); + } +} - e->file = ctx->file; /* Must happen prior to symtab_add() */ - e->containing_type = containing_type; +static uint64_t _upb_MessageDef_Modifiers(const upb_MessageDef* m) { + uint64_t out = 0; + if (upb_FileDef_Syntax(m->file) == kUpb_Syntax_Proto3) { + out |= kUpb_MessageModifier_ValidateUtf8; + out |= kUpb_MessageModifier_DefaultIsPacked; + } + if (m->ext_range_count) { + out |= kUpb_MessageModifier_IsExtendable; + } + return out; +} - name = google_protobuf_EnumDescriptorProto_name(enum_proto); - check_ident(ctx, name, false); +bool upb_MessageDef_MiniDescriptorEncode(const upb_MessageDef* m, upb_Arena* a, + upb_StringView* out) { + upb_DescState s; + _upb_DescState_Init(&s); - e->full_name = makefullname(ctx, prefix, name); - symtab_add(ctx, e->full_name, pack_def(e, UPB_DEFTYPE_ENUM)); + const upb_FieldDef** sorted = NULL; + if (!m->is_sorted) { + sorted = _upb_FieldDefs_Sorted(m->fields, m->field_count, a); + if (!sorted) return false; + } - values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n); - CHK_OOM(upb_strtable_init(&e->ntoi, n, ctx->arena)); - CHK_OOM(upb_inttable_init(&e->iton, ctx->arena)); + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = + upb_MtDataEncoder_StartMessage(&s.e, s.ptr, _upb_MessageDef_Modifiers(m)); - e->defaultval = 0; - e->value_count = n; - e->values = symtab_alloc(ctx, sizeof(*e->values) * n); + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = sorted ? sorted[i] : upb_MessageDef_Field(m, i); + const upb_FieldType type = upb_FieldDef_Type(f); + const int number = upb_FieldDef_Number(f); + const uint64_t modifiers = _upb_FieldDef_Modifiers(f); - if (n == 0) { - symtab_errf(ctx, "enums must contain at least one value (%s)", - e->full_name); + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_PutField(&s.e, s.ptr, type, number, modifiers); } - SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); - - for (i = 0; i < n; i++) { - create_enumvaldef(ctx, prefix, values[i], e, i); - } + for (int i = 0; i < m->oneof_count; i++) { + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_StartOneof(&s.e, s.ptr); - upb_inttable_compact(&e->iton, ctx->arena); + const upb_OneofDef* o = upb_MessageDef_Oneof(m, i); + const int field_count = upb_OneofDef_FieldCount(o); + for (int j = 0; j < field_count; j++) { + const int number = upb_FieldDef_Number(upb_OneofDef_Field(o, j)); - if (e->file->syntax == kUpb_Syntax_Proto2) { - if (ctx->layout) { - UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count); - e->layout = ctx->layout->enums[ctx->enum_count++]; - UPB_ASSERT(upb_inttable_count(&e->iton) == - e->layout->value_count + count_bits_debug(e->layout->mask)); - } else { - e->layout = create_enumlayout(ctx, e); + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_PutOneofField(&s.e, s.ptr, number); } - } else { - e->layout = NULL; } -} -static void msgdef_create_nested( - symtab_addctx* ctx, const google_protobuf_DescriptorProto* msg_proto, - upb_MessageDef* m); + if (!_upb_DescState_Grow(&s, a)) return false; + *s.ptr = '\0'; -static void create_msgdef(symtab_addctx* ctx, const char* prefix, + out->data = s.buf; + out->size = s.ptr - s.buf; + return true; +} + +static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, const google_protobuf_DescriptorProto* msg_proto, const upb_MessageDef* containing_type, - const upb_MessageDef* _m) { - upb_MessageDef* m = (upb_MessageDef*)_m; + upb_MessageDef* m) { const google_protobuf_OneofDescriptorProto* const* oneofs; const google_protobuf_FieldDescriptorProto* const* fields; const google_protobuf_DescriptorProto_ExtensionRange* const* ext_ranges; - size_t i, n_oneof, n_field, n_ext_range; + size_t n_oneof, n_field, n_ext_range, n_enum, n_ext, n_msg; upb_StringView name; - m->file = ctx->file; /* Must happen prior to symtab_add(). */ + // Must happen before _upb_DefBuilder_Add() + m->file = _upb_DefBuilder_File(ctx); + m->containing_type = containing_type; + m->is_sorted = true; name = google_protobuf_DescriptorProto_name(msg_proto); - check_ident(ctx, name, false); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); - m->full_name = makefullname(ctx, prefix, name); - symtab_add(ctx, m->full_name, pack_def(m, UPB_DEFTYPE_MSG)); + m->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + _upb_DefBuilder_Add(ctx, m->full_name, _upb_DefType_Pack(m, UPB_DEFTYPE_MSG)); oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n_oneof); fields = google_protobuf_DescriptorProto_field(msg_proto, &n_field); - ext_ranges = - google_protobuf_DescriptorProto_extension_range(msg_proto, &n_ext_range); + ext_ranges = google_protobuf_DescriptorProto_extension_range(msg_proto, &n_ext_range); - CHK_OOM(upb_inttable_init(&m->itof, ctx->arena)); - CHK_OOM(upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena)); + bool ok = upb_inttable_init(&m->itof, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); if (ctx->layout) { /* create_fielddef() below depends on this being set. */ @@ -7763,3321 +8725,3909 @@ static void create_msgdef(symtab_addctx* ctx, const char* prefix, UPB_ASSERT(n_field == m->layout->field_count); } else { /* Allocate now (to allow cross-linking), populate later. */ - m->layout = - symtab_alloc(ctx, sizeof(*m->layout) + sizeof(_upb_FastTable_Entry)); + m->layout = _upb_DefBuilder_Alloc( + ctx, sizeof(*m->layout) + sizeof(_upb_FastTable_Entry)); } - SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); + UBP_DEF_SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); m->oneof_count = n_oneof; - m->oneofs = symtab_alloc(ctx, sizeof(*m->oneofs) * n_oneof); - for (i = 0; i < n_oneof; i++) { - create_oneofdef(ctx, m, oneofs[i], &m->oneofs[i]); - } + m->oneofs = _upb_OneofDefs_New(ctx, n_oneof, oneofs, m); m->field_count = n_field; - m->fields = symtab_alloc(ctx, sizeof(*m->fields) * n_field); - for (i = 0; i < n_field; i++) { - create_fielddef(ctx, m->full_name, m, fields[i], &m->fields[i], - /* is_extension= */ false); - } + m->fields = + _upb_FieldDefs_New(ctx, n_field, fields, m->full_name, m, &m->is_sorted); m->ext_range_count = n_ext_range; - m->ext_ranges = symtab_alloc(ctx, sizeof(*m->ext_ranges) * n_ext_range); - for (i = 0; i < n_ext_range; i++) { - const google_protobuf_DescriptorProto_ExtensionRange* r = ext_ranges[i]; - upb_ExtensionRange* r_def = (upb_ExtensionRange*)&m->ext_ranges[i]; - int32_t start = google_protobuf_DescriptorProto_ExtensionRange_start(r); - int32_t end = google_protobuf_DescriptorProto_ExtensionRange_end(r); - int32_t max = - google_protobuf_MessageOptions_message_set_wire_format(m->opts) - ? INT32_MAX - : kUpb_MaxFieldNumber + 1; - - // A full validation would also check that each range is disjoint, and that - // none of the fields overlap with the extension ranges, but we are just - // sanity checking here. - if (start < 1 || end <= start || end > max) { - symtab_errf(ctx, "Extension range (%d, %d) is invalid, message=%s\n", - (int)start, (int)end, m->full_name); - } + m->ext_ranges = _upb_ExtensionRanges_New(ctx, n_ext_range, ext_ranges, m); - r_def->start = start; - r_def->end = end; - SET_OPTIONS(r_def->opts, DescriptorProto_ExtensionRange, - ExtensionRangeOptions, r); - } + const size_t synthetic_count = _upb_OneofDefs_Finalize(ctx, m); + m->real_oneof_count = m->oneof_count - synthetic_count; - finalize_oneofs(ctx, m); assign_msg_wellknowntype(m); upb_inttable_compact(&m->itof, ctx->arena); - msgdef_create_nested(ctx, msg_proto, m); -} - -static void msgdef_create_nested( - symtab_addctx* ctx, const google_protobuf_DescriptorProto* msg_proto, - upb_MessageDef* m) { - size_t n; const google_protobuf_EnumDescriptorProto* const* enums = - google_protobuf_DescriptorProto_enum_type(msg_proto, &n); - m->nested_enum_count = n; - m->nested_enums = symtab_alloc(ctx, sizeof(*m->nested_enums) * n); - for (size_t i = 0; i < n; i++) { - m->nested_enum_count = i + 1; - create_enumdef(ctx, m->full_name, enums[i], m, &m->nested_enums[i]); - } + google_protobuf_DescriptorProto_enum_type(msg_proto, &n_enum); + m->nested_enum_count = n_enum; + m->nested_enums = _upb_EnumDefs_New(ctx, n_enum, enums, m); const google_protobuf_FieldDescriptorProto* const* exts = - google_protobuf_DescriptorProto_extension(msg_proto, &n); - m->nested_ext_count = n; - m->nested_exts = symtab_alloc(ctx, sizeof(*m->nested_exts) * n); - for (size_t i = 0; i < n; i++) { - create_fielddef(ctx, m->full_name, m, exts[i], &m->nested_exts[i], - /* is_extension= */ true); - ((upb_FieldDef*)&m->nested_exts[i])->index_ = i; - } + google_protobuf_DescriptorProto_extension(msg_proto, &n_ext); + m->nested_ext_count = n_ext; + m->nested_exts = _upb_FieldDefs_New(ctx, n_ext, exts, m->full_name, m, NULL); const google_protobuf_DescriptorProto* const* msgs = - google_protobuf_DescriptorProto_nested_type(msg_proto, &n); - m->nested_msg_count = n; - m->nested_msgs = symtab_alloc(ctx, sizeof(*m->nested_msgs) * n); - for (size_t i = 0; i < n; i++) { - create_msgdef(ctx, m->full_name, msgs[i], m, &m->nested_msgs[i]); - } -} - -static void resolve_subdef(symtab_addctx* ctx, const char* prefix, - upb_FieldDef* f) { - const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; - upb_StringView name = - google_protobuf_FieldDescriptorProto_type_name(field_proto); - bool has_name = - google_protobuf_FieldDescriptorProto_has_type_name(field_proto); - switch ((int)f->type_) { - case FIELD_TYPE_UNSPECIFIED: { - // Type was not specified and must be inferred. - UPB_ASSERT(has_name); - upb_deftype_t type; - const void* def = - symtab_resolveany(ctx, f->full_name, prefix, name, &type); - switch (type) { - case UPB_DEFTYPE_ENUM: - f->sub.enumdef = def; - f->type_ = kUpb_FieldType_Enum; - break; - case UPB_DEFTYPE_MSG: - f->sub.msgdef = def; - f->type_ = kUpb_FieldType_Message; // It appears there is no way of - // this being a group. - break; - default: - symtab_errf(ctx, "Couldn't resolve type name for field %s", - f->full_name); - } - } - case kUpb_FieldType_Message: - case kUpb_FieldType_Group: - UPB_ASSERT(has_name); - f->sub.msgdef = - symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); - break; - case kUpb_FieldType_Enum: - UPB_ASSERT(has_name); - f->sub.enumdef = - symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_ENUM); - break; - default: - // No resolution necessary. - break; - } + google_protobuf_DescriptorProto_nested_type(msg_proto, &n_msg); + m->nested_msg_count = n_msg; + m->nested_msgs = _upb_MessageDefs_New(ctx, n_msg, msgs, m); } -static void resolve_extension( - symtab_addctx* ctx, const char* prefix, upb_FieldDef* f, - const google_protobuf_FieldDescriptorProto* field_proto) { - if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) { - symtab_errf(ctx, "extension for field '%s' had no extendee", f->full_name); - } - - upb_StringView name = - google_protobuf_FieldDescriptorProto_extendee(field_proto); - const upb_MessageDef* m = - symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); - f->msgdef = m; - - bool found = false; - - for (int i = 0, n = m->ext_range_count; i < n; i++) { - const upb_ExtensionRange* r = &m->ext_ranges[i]; - if (r->start <= f->number_ && f->number_ < r->end) { - found = true; - break; - } - } +// Allocate and initialize an array of |n| message defs. +upb_MessageDef* _upb_MessageDefs_New( + upb_DefBuilder* ctx, int n, const google_protobuf_DescriptorProto* const* protos, + const upb_MessageDef* containing_type) { + _upb_DefType_CheckPadding(sizeof(upb_MessageDef)); - if (!found) { - symtab_errf(ctx, - "field number %u in extension %s has no extension range in " - "message %s", - (unsigned)f->number_, f->full_name, f->msgdef->full_name); - } + const char* name = containing_type ? containing_type->full_name + : _upb_FileDef_RawPackage(ctx->file); - const upb_MiniTable_Extension* ext = ctx->file->ext_layouts[f->layout_index]; - if (ctx->layout) { - UPB_ASSERT(upb_FieldDef_Number(f) == ext->field.number); - } else { - upb_MiniTable_Extension* mut_ext = (upb_MiniTable_Extension*)ext; - fill_fieldlayout(&mut_ext->field, f); - mut_ext->field.presence = 0; - mut_ext->field.offset = 0; - mut_ext->field.submsg_index = 0; - mut_ext->extendee = f->msgdef->layout; - mut_ext->sub.submsg = f->sub.msgdef->layout; + upb_MessageDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MessageDef) * n); + for (int i = 0; i < n; i++) { + create_msgdef(ctx, name, protos[i], containing_type, &m[i]); } - - CHK_OOM(upb_inttable_insert(&ctx->symtab->exts, (uintptr_t)ext, - upb_value_constptr(f), ctx->arena)); + return m; } -static void resolve_default( - symtab_addctx* ctx, upb_FieldDef* f, - const google_protobuf_FieldDescriptorProto* field_proto) { - // Have to delay resolving of the default value until now because of the enum - // case, since enum defaults are specified with a label. - if (google_protobuf_FieldDescriptorProto_has_default_value(field_proto)) { - upb_StringView defaultval = - google_protobuf_FieldDescriptorProto_default_value(field_proto); - - if (f->file->syntax == kUpb_Syntax_Proto3) { - symtab_errf(ctx, "proto3 fields cannot have explicit defaults (%s)", - f->full_name); - } - if (upb_FieldDef_IsSubMessage(f)) { - symtab_errf(ctx, "message fields cannot have explicit defaults (%s)", - f->full_name); - } - parse_default(ctx, defaultval.data, defaultval.size, f); - f->has_default = true; - } else { - set_default_default(ctx, f); - f->has_default = false; - } -} +// Must be last. -static void resolve_fielddef(symtab_addctx* ctx, const char* prefix, - upb_FieldDef* f) { - // We have to stash this away since resolve_subdef() may overwrite it. - const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; +struct upb_MethodDef { + const google_protobuf_MethodOptions* opts; + upb_ServiceDef* service; + const char* full_name; + const upb_MessageDef* input_type; + const upb_MessageDef* output_type; + int index; + bool client_streaming; + bool server_streaming; +}; - resolve_subdef(ctx, prefix, f); - resolve_default(ctx, f, field_proto); +upb_MethodDef* _upb_MethodDef_At(const upb_MethodDef* m, int i) { + return (upb_MethodDef*)&m[i]; +} - if (f->is_extension_) { - resolve_extension(ctx, prefix, f, field_proto); - } +const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m) { + return m->service; } -static void resolve_msgdef(symtab_addctx* ctx, upb_MessageDef* m) { - for (int i = 0; i < m->field_count; i++) { - resolve_fielddef(ctx, m->full_name, (upb_FieldDef*)&m->fields[i]); - } +const google_protobuf_MethodOptions* upb_MethodDef_Options(const upb_MethodDef* m) { + return m->opts; +} - m->in_message_set = false; - for (int i = 0; i < m->nested_ext_count; i++) { - upb_FieldDef* ext = (upb_FieldDef*)&m->nested_exts[i]; - resolve_fielddef(ctx, m->full_name, ext); - if (ext->type_ == kUpb_FieldType_Message && - ext->label_ == kUpb_Label_Optional && ext->sub.msgdef == m && - google_protobuf_MessageOptions_message_set_wire_format( - ext->msgdef->opts)) { - m->in_message_set = true; - } - } +bool upb_MethodDef_HasOptions(const upb_MethodDef* m) { + return m->opts != (void*)kUpbDefOptDefault; +} - if (!ctx->layout) make_layout(ctx, m); +const char* upb_MethodDef_FullName(const upb_MethodDef* m) { + return m->full_name; +} - for (int i = 0; i < m->nested_msg_count; i++) { - resolve_msgdef(ctx, (upb_MessageDef*)&m->nested_msgs[i]); - } +const char* upb_MethodDef_Name(const upb_MethodDef* m) { + return _upb_DefBuilder_FullToShort(m->full_name); } -static int count_exts_in_msg(const google_protobuf_DescriptorProto* msg_proto) { - size_t n; - google_protobuf_DescriptorProto_extension(msg_proto, &n); - int ext_count = n; +int upb_MethodDef_Index(const upb_MethodDef* m) { return m->index; } - const google_protobuf_DescriptorProto* const* nested_msgs = - google_protobuf_DescriptorProto_nested_type(msg_proto, &n); - for (size_t i = 0; i < n; i++) { - ext_count += count_exts_in_msg(nested_msgs[i]); - } +const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m) { + return m->input_type; +} - return ext_count; +const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m) { + return m->output_type; } -static void build_filedef( - symtab_addctx* ctx, upb_FileDef* file, - const google_protobuf_FileDescriptorProto* file_proto) { - const google_protobuf_DescriptorProto* const* msgs; - const google_protobuf_EnumDescriptorProto* const* enums; - const google_protobuf_FieldDescriptorProto* const* exts; - const google_protobuf_ServiceDescriptorProto* const* services; - const upb_StringView* strs; - const int32_t* public_deps; - const int32_t* weak_deps; - size_t i, n; +bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m) { + return m->client_streaming; +} - file->symtab = ctx->symtab; +bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { + return m->server_streaming; +} - /* Count all extensions in the file, to build a flat array of layouts. */ - google_protobuf_FileDescriptorProto_extension(file_proto, &n); - int ext_count = n; - msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); +static void create_method(upb_DefBuilder* ctx, + const google_protobuf_MethodDescriptorProto* method_proto, + upb_ServiceDef* s, upb_MethodDef* m) { + upb_StringView name = google_protobuf_MethodDescriptorProto_name(method_proto); + + m->service = s; + m->full_name = + _upb_DefBuilder_MakeFullName(ctx, upb_ServiceDef_FullName(s), name); + m->client_streaming = + google_protobuf_MethodDescriptorProto_client_streaming(method_proto); + m->server_streaming = + google_protobuf_MethodDescriptorProto_server_streaming(method_proto); + m->input_type = _upb_DefBuilder_Resolve( + ctx, m->full_name, m->full_name, + google_protobuf_MethodDescriptorProto_input_type(method_proto), UPB_DEFTYPE_MSG); + m->output_type = _upb_DefBuilder_Resolve( + ctx, m->full_name, m->full_name, + google_protobuf_MethodDescriptorProto_output_type(method_proto), UPB_DEFTYPE_MSG); + + UBP_DEF_SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, + method_proto); +} + +// Allocate and initialize an array of |n| method defs belonging to |s|. +upb_MethodDef* _upb_MethodDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_MethodDescriptorProto* const* protos, upb_ServiceDef* s) { + upb_MethodDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MethodDef) * n); for (int i = 0; i < n; i++) { - ext_count += count_exts_in_msg(msgs[i]); + create_method(ctx, protos[i], s, &m[i]); + m[i].index = i; } - file->ext_count = ext_count; + return m; +} - if (ctx->layout) { - /* We are using the ext layouts that were passed in. */ - file->ext_layouts = ctx->layout->exts; - if (ctx->layout->ext_count != file->ext_count) { - symtab_errf(ctx, "Extension count did not match layout (%d vs %d)", - ctx->layout->ext_count, file->ext_count); - } - } else { - /* We are building ext layouts from scratch. */ - file->ext_layouts = - symtab_alloc(ctx, sizeof(*file->ext_layouts) * file->ext_count); - upb_MiniTable_Extension* ext = - symtab_alloc(ctx, sizeof(*ext) * file->ext_count); - for (int i = 0; i < file->ext_count; i++) { - file->ext_layouts[i] = &ext[i]; - } - } - if (!google_protobuf_FileDescriptorProto_has_name(file_proto)) { - symtab_errf(ctx, "File has no name"); - } +#include +#include +#include - file->name = - strviewdup(ctx, google_protobuf_FileDescriptorProto_name(file_proto)); - if (google_protobuf_FileDescriptorProto_has_package(file_proto)) { - upb_StringView package = - google_protobuf_FileDescriptorProto_package(file_proto); - check_ident(ctx, package, true); - file->package = strviewdup(ctx, package); - } else { - file->package = NULL; - } +// Must be last. - if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) { - upb_StringView syntax = - google_protobuf_FileDescriptorProto_syntax(file_proto); +struct upb_OneofDef { + const google_protobuf_OneofOptions* opts; + const upb_MessageDef* parent; + const char* full_name; + int field_count; + bool synthetic; + const upb_FieldDef** fields; + upb_strtable ntof; // lookup a field by name + upb_inttable itof; // lookup a field by number (index) +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif +}; - if (streql_view(syntax, "proto2")) { - file->syntax = kUpb_Syntax_Proto2; - } else if (streql_view(syntax, "proto3")) { - file->syntax = kUpb_Syntax_Proto3; - } else { - symtab_errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", - UPB_STRINGVIEW_ARGS(syntax)); - } - } else { - file->syntax = kUpb_Syntax_Proto2; - } +upb_OneofDef* _upb_OneofDef_At(const upb_OneofDef* o, int i) { + return (upb_OneofDef*)&o[i]; +} - /* Read options. */ - SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); +const google_protobuf_OneofOptions* upb_OneofDef_Options(const upb_OneofDef* o) { + return o->opts; +} - /* Verify dependencies. */ - strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n); - file->dep_count = n; - file->deps = symtab_alloc(ctx, sizeof(*file->deps) * n); +bool upb_OneofDef_HasOptions(const upb_OneofDef* o) { + return o->opts != (void*)kUpbDefOptDefault; +} - for (i = 0; i < n; i++) { - upb_StringView str = strs[i]; - file->deps[i] = - upb_DefPool_FindFileByNameWithSize(ctx->symtab, str.data, str.size); - if (!file->deps[i]) { - symtab_errf(ctx, - "Depends on file '" UPB_STRINGVIEW_FORMAT - "', but it has not been loaded", - UPB_STRINGVIEW_ARGS(str)); - } - } +const char* upb_OneofDef_FullName(const upb_OneofDef* o) { + return o->full_name; +} - public_deps = - google_protobuf_FileDescriptorProto_public_dependency(file_proto, &n); - file->public_dep_count = n; - file->public_deps = symtab_alloc(ctx, sizeof(*file->public_deps) * n); - int32_t* mutable_public_deps = (int32_t*)file->public_deps; - for (i = 0; i < n; i++) { - if (public_deps[i] >= file->dep_count) { - symtab_errf(ctx, "public_dep %d is out of range", (int)public_deps[i]); - } - mutable_public_deps[i] = public_deps[i]; - } +const char* upb_OneofDef_Name(const upb_OneofDef* o) { + return _upb_DefBuilder_FullToShort(o->full_name); +} - weak_deps = - google_protobuf_FileDescriptorProto_weak_dependency(file_proto, &n); - file->weak_dep_count = n; - file->weak_deps = symtab_alloc(ctx, sizeof(*file->weak_deps) * n); - int32_t* mutable_weak_deps = (int32_t*)file->weak_deps; - for (i = 0; i < n; i++) { - if (weak_deps[i] >= file->dep_count) { - symtab_errf(ctx, "weak_dep %d is out of range", (int)weak_deps[i]); - } - mutable_weak_deps[i] = weak_deps[i]; - } +const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o) { + return o->parent; +} - /* Create enums. */ - enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); - file->top_lvl_enum_count = n; - file->top_lvl_enums = symtab_alloc(ctx, sizeof(*file->top_lvl_enums) * n); - for (i = 0; i < n; i++) { - create_enumdef(ctx, file->package, enums[i], NULL, &file->top_lvl_enums[i]); - } +int upb_OneofDef_FieldCount(const upb_OneofDef* o) { return o->field_count; } - /* Create extensions. */ - exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n); - file->top_lvl_ext_count = n; - file->top_lvl_exts = symtab_alloc(ctx, sizeof(*file->top_lvl_exts) * n); - for (i = 0; i < n; i++) { - create_fielddef(ctx, file->package, NULL, exts[i], &file->top_lvl_exts[i], - /* is_extension= */ true); - ((upb_FieldDef*)&file->top_lvl_exts[i])->index_ = i; - } +const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i) { + UPB_ASSERT(i < o->field_count); + return o->fields[i]; +} - /* Create messages. */ - msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); - file->top_lvl_msg_count = n; - file->top_lvl_msgs = symtab_alloc(ctx, sizeof(*file->top_lvl_msgs) * n); - for (i = 0; i < n; i++) { - create_msgdef(ctx, file->package, msgs[i], NULL, &file->top_lvl_msgs[i]); - } +int upb_OneofDef_numfields(const upb_OneofDef* o) { return o->field_count; } - /* Create services. */ - services = google_protobuf_FileDescriptorProto_service(file_proto, &n); - file->service_count = n; - file->services = symtab_alloc(ctx, sizeof(*file->services) * n); - for (i = 0; i < n; i++) { - create_service(ctx, services[i], &file->services[i]); - ((upb_ServiceDef*)&file->services[i])->index = i; - } +uint32_t upb_OneofDef_Index(const upb_OneofDef* o) { + // Compute index in our parent's array. + return o - upb_MessageDef_Oneof(o->parent, 0); +} - /* Now that all names are in the table, build layouts and resolve refs. */ - for (i = 0; i < (size_t)file->top_lvl_ext_count; i++) { - resolve_fielddef(ctx, file->package, (upb_FieldDef*)&file->top_lvl_exts[i]); - } +bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o) { return o->synthetic; } - for (i = 0; i < (size_t)file->top_lvl_msg_count; i++) { - resolve_msgdef(ctx, (upb_MessageDef*)&file->top_lvl_msgs[i]); - } +const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, + const char* name, + size_t size) { + upb_value val; + return upb_strtable_lookup2(&o->ntof, name, size, &val) + ? upb_value_getptr(val) + : NULL; +} - if (file->ext_count) { - CHK_OOM(_upb_extreg_add(ctx->symtab->extreg, file->ext_layouts, - file->ext_count)); - } +const upb_FieldDef* upb_OneofDef_LookupName(const upb_OneofDef* o, + const char* name) { + return upb_OneofDef_LookupNameWithSize(o, name, strlen(name)); } -static void remove_filedef(upb_DefPool* s, upb_FileDef* file) { - intptr_t iter = UPB_INTTABLE_BEGIN; - upb_StringView key; +const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, + uint32_t num) { upb_value val; - while (upb_strtable_next2(&s->syms, &key, &val, &iter)) { - const upb_FileDef* f; - switch (deftype(val)) { - case UPB_DEFTYPE_EXT: - f = upb_FieldDef_File(unpack_def(val, UPB_DEFTYPE_EXT)); - break; - case UPB_DEFTYPE_MSG: - f = upb_MessageDef_File(unpack_def(val, UPB_DEFTYPE_MSG)); - break; - case UPB_DEFTYPE_ENUM: - f = upb_EnumDef_File(unpack_def(val, UPB_DEFTYPE_ENUM)); - break; - case UPB_DEFTYPE_ENUMVAL: - f = upb_EnumDef_File( - upb_EnumValueDef_Enum(unpack_def(val, UPB_DEFTYPE_ENUMVAL))); - break; - case UPB_DEFTYPE_SERVICE: - f = upb_ServiceDef_File(unpack_def(val, UPB_DEFTYPE_SERVICE)); - break; - default: - UPB_UNREACHABLE(); - } + return upb_inttable_lookup(&o->itof, num, &val) ? upb_value_getptr(val) + : NULL; +} - if (f == file) upb_strtable_removeiter(&s->syms, &iter); - } +bool _upb_OneofDef_Insert(upb_OneofDef* o, const upb_FieldDef* f, + const char* name, size_t size, upb_Arena* a) { + o->field_count++; + if (_upb_FieldDef_IsProto3Optional(f)) o->synthetic = true; + + const int number = upb_FieldDef_Number(f); + const upb_value v = upb_value_constptr(f); + return upb_inttable_insert(&o->itof, number, v, a) && + upb_strtable_insert(&o->ntof, name, size, v, a); } -static const upb_FileDef* _upb_DefPool_AddFile( - upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, - const upb_MiniTable_File* layout, upb_Status* status) { - symtab_addctx ctx; - upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto); - upb_value v; +// Returns the synthetic count. +size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m) { + int synthetic_count = 0; - if (upb_strtable_lookup2(&s->files, name.data, name.size, &v)) { - if (unpack_def(v, UPB_DEFTYPE_FILE)) { - upb_Status_SetErrorFormat(status, "duplicate file name (%.*s)", - UPB_STRINGVIEW_ARGS(name)); - return NULL; - } - const upb_MiniTable_File* registered = unpack_def(v, UPB_DEFTYPE_LAYOUT); - UPB_ASSERT(registered); - if (layout && layout != registered) { - upb_Status_SetErrorFormat( - status, "tried to build with a different layout (filename=%.*s)", - UPB_STRINGVIEW_ARGS(name)); - return NULL; + for (int i = 0; i < upb_MessageDef_OneofCount(m); i++) { + upb_OneofDef* o = (upb_OneofDef*)upb_MessageDef_Oneof(m, i); + + if (o->synthetic && o->field_count != 1) { + _upb_DefBuilder_Errf(ctx, + "Synthetic oneofs must have one field, not %d: %s", + o->field_count, upb_OneofDef_Name(o)); } - layout = registered; - } - ctx.symtab = s; - ctx.layout = layout; - ctx.msg_count = 0; - ctx.enum_count = 0; - ctx.ext_count = 0; - ctx.status = status; - ctx.file = NULL; - ctx.arena = upb_Arena_New(); - ctx.tmp_arena = upb_Arena_New(); + if (o->synthetic) { + synthetic_count++; + } else if (synthetic_count != 0) { + _upb_DefBuilder_Errf( + ctx, "Synthetic oneofs must be after all other oneofs: %s", + upb_OneofDef_Name(o)); + } - if (!ctx.arena || !ctx.tmp_arena) { - if (ctx.arena) upb_Arena_Free(ctx.arena); - if (ctx.tmp_arena) upb_Arena_Free(ctx.tmp_arena); - upb_Status_setoom(status); - return NULL; + o->fields = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef*) * o->field_count); + o->field_count = 0; } - if (UPB_UNLIKELY(UPB_SETJMP(ctx.err))) { - UPB_ASSERT(!upb_Status_IsOk(status)); - if (ctx.file) { - remove_filedef(s, ctx.file); - ctx.file = NULL; + for (int i = 0; i < upb_MessageDef_FieldCount(m); i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + upb_OneofDef* o = (upb_OneofDef*)upb_FieldDef_ContainingOneof(f); + if (o) { + o->fields[o->field_count++] = f; } - } else { - ctx.file = symtab_alloc(&ctx, sizeof(*ctx.file)); - build_filedef(&ctx, ctx.file, file_proto); - upb_strtable_insert(&s->files, name.data, name.size, - pack_def(ctx.file, UPB_DEFTYPE_FILE), ctx.arena); - UPB_ASSERT(upb_Status_IsOk(status)); - upb_Arena_Fuse(s->arena, ctx.arena); } - upb_Arena_Free(ctx.arena); - upb_Arena_Free(ctx.tmp_arena); - return ctx.file; -} - -const upb_FileDef* upb_DefPool_AddFile( - upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, - upb_Status* status) { - return _upb_DefPool_AddFile(s, file_proto, NULL, status); + return synthetic_count; } -/* Include here since we want most of this file to be stdio-free. */ -#include +static void create_oneofdef(upb_DefBuilder* ctx, upb_MessageDef* m, + const google_protobuf_OneofDescriptorProto* oneof_proto, + const upb_OneofDef* _o) { + upb_OneofDef* o = (upb_OneofDef*)_o; + upb_StringView name = google_protobuf_OneofDescriptorProto_name(oneof_proto); -bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, - bool rebuild_minitable) { - /* Since this function should never fail (it would indicate a bug in upb) we - * print errors to stderr instead of returning error status to the user. */ - _upb_DefPool_Init** deps = init->deps; - google_protobuf_FileDescriptorProto* file; - upb_Arena* arena; - upb_Status status; + o->parent = m; + o->full_name = + _upb_DefBuilder_MakeFullName(ctx, upb_MessageDef_FullName(m), name); + o->field_count = 0; + o->synthetic = false; - upb_Status_Clear(&status); + UBP_DEF_SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); - if (upb_DefPool_FindFileByName(s, init->filename)) { - return true; + if (upb_MessageDef_FindByNameWithSize(m, name.data, name.size, NULL, NULL)) { + _upb_DefBuilder_Errf(ctx, "duplicate oneof name (%s)", o->full_name); } - arena = upb_Arena_New(); + upb_value v = _upb_DefType_Pack(o, UPB_DEFTYPE_ONEOF); + bool ok = _upb_MessageDef_Insert(m, name.data, name.size, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); - for (; *deps; deps++) { - if (!_upb_DefPool_LoadDefInitEx(s, *deps, rebuild_minitable)) goto err; - } + ok = upb_inttable_init(&o->itof, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); - file = google_protobuf_FileDescriptorProto_parse_ex( - init->descriptor.data, init->descriptor.size, NULL, - kUpb_DecodeOption_AliasString, arena); - s->bytes_loaded += init->descriptor.size; + ok = upb_strtable_init(&o->ntof, 4, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} - if (!file) { - upb_Status_SetErrorFormat( - &status, - "Failed to parse compiled-in descriptor for file '%s'. This should " - "never happen.", - init->filename); - goto err; - } +// Allocate and initialize an array of |n| oneof defs. +upb_OneofDef* _upb_OneofDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_OneofDescriptorProto* const* protos, upb_MessageDef* m) { + _upb_DefType_CheckPadding(sizeof(upb_OneofDef)); - const upb_MiniTable_File* mt = rebuild_minitable ? NULL : init->layout; - if (!_upb_DefPool_AddFile(s, file, mt, &status)) { - goto err; + upb_OneofDef* o = _upb_DefBuilder_Alloc(ctx, sizeof(upb_OneofDef) * n); + for (int i = 0; i < n; i++) { + create_oneofdef(ctx, m, protos[i], &o[i]); } + return o; +} - upb_Arena_Free(arena); - return true; -err: - fprintf(stderr, - "Error loading compiled-in descriptor for file '%s' (this should " - "never happen): %s\n", - init->filename, upb_Status_ErrorMessage(&status)); - upb_Arena_Free(arena); - return false; + +// Must be last. + +struct upb_ServiceDef { + const google_protobuf_ServiceOptions* opts; + const upb_FileDef* file; + const char* full_name; + upb_MethodDef* methods; + int method_count; + int index; +}; + +upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int index) { + return (upb_ServiceDef*)&s[index]; } -size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s) { - return s->bytes_loaded; +const google_protobuf_ServiceOptions* upb_ServiceDef_Options(const upb_ServiceDef* s) { + return s->opts; } -upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s) { return s->arena; } +bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s) { + return s->opts != (void*)kUpbDefOptDefault; +} -const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable( - const upb_DefPool* s, const upb_MiniTable_Extension* ext) { - upb_value v; - bool ok = upb_inttable_lookup(&s->exts, (uintptr_t)ext, &v); - UPB_ASSERT(ok); - return upb_value_getconstptr(v); +const char* upb_ServiceDef_FullName(const upb_ServiceDef* s) { + return s->full_name; } -const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, - const upb_MessageDef* m, - int32_t fieldnum) { - const upb_MiniTable* l = upb_MessageDef_MiniTable(m); - const upb_MiniTable_Extension* ext = _upb_extreg_get(s->extreg, l, fieldnum); - return ext ? _upb_DefPool_FindExtensionByMiniTable(s, ext) : NULL; +const char* upb_ServiceDef_Name(const upb_ServiceDef* s) { + return _upb_DefBuilder_FullToShort(s->full_name); +} + +int upb_ServiceDef_Index(const upb_ServiceDef* s) { return s->index; } + +const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s) { + return s->file; +} + +int upb_ServiceDef_MethodCount(const upb_ServiceDef* s) { + return s->method_count; +} + +const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i) { + return (i < 0 || i >= s->method_count) ? NULL + : _upb_MethodDef_At(s->methods, i); +} + +const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, + const char* name) { + for (int i = 0; i < s->method_count; i++) { + const upb_MethodDef* m = _upb_MethodDef_At(s->methods, i); + if (strcmp(name, upb_MethodDef_Name(m)) == 0) { + return m; + } + } + return NULL; } -bool _upb_DefPool_registerlayout(upb_DefPool* s, const char* filename, - const upb_MiniTable_File* file) { - if (upb_DefPool_FindFileByName(s, filename)) return false; - upb_value v = pack_def(file, UPB_DEFTYPE_LAYOUT); - return upb_strtable_insert(&s->files, filename, strlen(filename), v, - s->arena); -} +static void create_service(upb_DefBuilder* ctx, + const google_protobuf_ServiceDescriptorProto* svc_proto, + upb_ServiceDef* s) { + upb_StringView name; + size_t n; -const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( - const upb_DefPool* s) { - return s->extreg; + // Must happen before _upb_DefBuilder_Add() + s->file = _upb_DefBuilder_File(ctx); + + name = google_protobuf_ServiceDescriptorProto_name(svc_proto); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); + const char* package = _upb_FileDef_RawPackage(s->file); + s->full_name = _upb_DefBuilder_MakeFullName(ctx, package, name); + _upb_DefBuilder_Add(ctx, s->full_name, + _upb_DefType_Pack(s, UPB_DEFTYPE_SERVICE)); + + const google_protobuf_MethodDescriptorProto* const* methods = + google_protobuf_ServiceDescriptorProto_method(svc_proto, &n); + s->method_count = n; + s->methods = _upb_MethodDefs_New(ctx, n, methods, s); + + UBP_DEF_SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, + svc_proto); } -const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, - const upb_MessageDef* m, - size_t* count) { - size_t n = 0; - intptr_t iter = UPB_INTTABLE_BEGIN; - uintptr_t key; - upb_value val; - // This is O(all exts) instead of O(exts for m). If we need this to be - // efficient we may need to make extreg into a two-level table, or have a - // second per-message index. - while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { - const upb_FieldDef* f = upb_value_getconstptr(val); - if (upb_FieldDef_ContainingType(f) == m) n++; - } - const upb_FieldDef** exts = malloc(n * sizeof(*exts)); - iter = UPB_INTTABLE_BEGIN; - size_t i = 0; - while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { - const upb_FieldDef* f = upb_value_getconstptr(val); - if (upb_FieldDef_ContainingType(f) == m) exts[i++] = f; +upb_ServiceDef* _upb_ServiceDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_ServiceDescriptorProto* const* protos) { + _upb_DefType_CheckPadding(sizeof(upb_ServiceDef)); + + upb_ServiceDef* s = _upb_DefBuilder_Alloc(ctx, sizeof(upb_ServiceDef) * n); + for (int i = 0; i < n; i++) { + create_service(ctx, protos[i], &s[i]); + s[i].index = i; } - *count = n; - return exts; + return s; } -#undef CHK_OOM +/* + * upb_table Implementation + * + * Implementation is heavily inspired by Lua's ltable.c. + */ -/** upb/reflection.c ************************************************************/ #include +// Must be last. -static size_t get_field_size(const upb_MiniTable_Field* f) { - static unsigned char sizes[] = { - 0, /* 0 */ - 8, /* kUpb_FieldType_Double */ - 4, /* kUpb_FieldType_Float */ - 8, /* kUpb_FieldType_Int64 */ - 8, /* kUpb_FieldType_UInt64 */ - 4, /* kUpb_FieldType_Int32 */ - 8, /* kUpb_FieldType_Fixed64 */ - 4, /* kUpb_FieldType_Fixed32 */ - 1, /* kUpb_FieldType_Bool */ - sizeof(upb_StringView), /* kUpb_FieldType_String */ - sizeof(void*), /* kUpb_FieldType_Group */ - sizeof(void*), /* kUpb_FieldType_Message */ - sizeof(upb_StringView), /* kUpb_FieldType_Bytes */ - 4, /* kUpb_FieldType_UInt32 */ - 4, /* kUpb_FieldType_Enum */ - 4, /* kUpb_FieldType_SFixed32 */ - 8, /* kUpb_FieldType_SFixed64 */ - 4, /* kUpb_FieldType_SInt32 */ - 8, /* kUpb_FieldType_SInt64 */ - }; - return upb_IsRepeatedOrMap(f) ? sizeof(void*) : sizes[f->descriptortype]; +#define UPB_MAXARRSIZE 16 /* 64k. */ + +/* From Chromium. */ +#define ARRAY_SIZE(x) \ + ((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x]))))) + +static const double MAX_LOAD = 0.85; + +/* The minimum utilization of the array part of a mixed hash/array table. This + * is a speed/memory-usage tradeoff (though it's not straightforward because of + * cache effects). The lower this is, the more memory we'll use. */ +static const double MIN_DENSITY = 0.1; + +static bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; } + +static upb_value _upb_value_val(uint64_t val) { + upb_value ret; + _upb_value_setval(&ret, val); + return ret; } -/* Strings/bytes are special-cased in maps. */ -static char _upb_CTypeo_mapsize[12] = { - 0, - 1, /* kUpb_CType_Bool */ - 4, /* kUpb_CType_Float */ - 4, /* kUpb_CType_Int32 */ - 4, /* kUpb_CType_UInt32 */ - 4, /* kUpb_CType_Enum */ - sizeof(void*), /* kUpb_CType_Message */ - 8, /* kUpb_CType_Double */ - 8, /* kUpb_CType_Int64 */ - 8, /* kUpb_CType_UInt64 */ - 0, /* kUpb_CType_String */ - 0, /* kUpb_CType_Bytes */ -}; +static int log2ceil(uint64_t v) { + int ret = 0; + bool pow2 = is_pow2(v); + while (v >>= 1) ret++; + ret = pow2 ? ret : ret + 1; /* Ceiling. */ + return UPB_MIN(UPB_MAXARRSIZE, ret); +} -static const char _upb_CTypeo_sizelg2[12] = { - 0, - 0, /* kUpb_CType_Bool */ - 2, /* kUpb_CType_Float */ - 2, /* kUpb_CType_Int32 */ - 2, /* kUpb_CType_UInt32 */ - 2, /* kUpb_CType_Enum */ - UPB_SIZE(2, 3), /* kUpb_CType_Message */ - 3, /* kUpb_CType_Double */ - 3, /* kUpb_CType_Int64 */ - 3, /* kUpb_CType_UInt64 */ - UPB_SIZE(3, 4), /* kUpb_CType_String */ - UPB_SIZE(3, 4), /* kUpb_CType_Bytes */ -}; +char* upb_strdup2(const char* s, size_t len, upb_Arena* a) { + size_t n; + char* p; + + /* Prevent overflow errors. */ + if (len == SIZE_MAX) return NULL; + /* Always null-terminate, even if binary data; but don't rely on the input to + * have a null-terminating byte since it may be a raw binary buffer. */ + n = len + 1; + p = upb_Arena_Malloc(a, n); + if (p) { + memcpy(p, s, len); + p[len] = 0; + } + return p; +} -/** upb_Message - * *******************************************************************/ +/* A type to represent the lookup key of either a strtable or an inttable. */ +typedef union { + uintptr_t num; + struct { + const char* str; + size_t len; + } str; +} lookupkey_t; -upb_Message* upb_Message_New(const upb_MessageDef* m, upb_Arena* a) { - return _upb_Message_New(upb_MessageDef_MiniTable(m), a); +static lookupkey_t strkey2(const char* str, size_t len) { + lookupkey_t k; + k.str.str = str; + k.str.len = len; + return k; } -static bool in_oneof(const upb_MiniTable_Field* field) { - return field->presence < 0; +static lookupkey_t intkey(uintptr_t key) { + lookupkey_t k; + k.num = key; + return k; } -static upb_MessageValue _upb_Message_Getraw(const upb_Message* msg, - const upb_FieldDef* f) { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - const char* mem = UPB_PTR_AT(msg, field->offset, char); - upb_MessageValue val = {0}; - memcpy(&val, mem, get_field_size(field)); - return val; +typedef uint32_t hashfunc_t(upb_tabkey key); +typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2); + +/* Base table (shared code) ***************************************************/ + +static uint32_t upb_inthash(uintptr_t key) { return (uint32_t)key; } + +static const upb_tabent* upb_getentry(const upb_table* t, uint32_t hash) { + return t->entries + (hash & t->mask); } -bool upb_Message_Has(const upb_Message* msg, const upb_FieldDef* f) { - assert(upb_FieldDef_HasPresence(f)); - if (upb_FieldDef_IsExtension(f)) { - const upb_MiniTable_Extension* ext = _upb_FieldDef_ExtensionMiniTable(f); - return _upb_Message_Getext(msg, ext) != NULL; +static bool upb_arrhas(upb_tabval key) { return key.val != (uint64_t)-1; } + +static bool isfull(upb_table* t) { return t->count == t->max_count; } + +static bool init(upb_table* t, uint8_t size_lg2, upb_Arena* a) { + size_t bytes; + + t->count = 0; + t->size_lg2 = size_lg2; + t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0; + t->max_count = upb_table_size(t) * MAX_LOAD; + bytes = upb_table_size(t) * sizeof(upb_tabent); + if (bytes > 0) { + t->entries = upb_Arena_Malloc(a, bytes); + if (!t->entries) return false; + memset(t->entries, 0, bytes); } else { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - if (in_oneof(field)) { - return _upb_getoneofcase_field(msg, field) == field->number; - } else if (field->presence > 0) { - return _upb_hasbit_field(msg, field); - } else { - UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message || - field->descriptortype == kUpb_FieldType_Group); - return _upb_Message_Getraw(msg, f).msg_val != NULL; - } + t->entries = NULL; } + return true; } -const upb_FieldDef* upb_Message_WhichOneof(const upb_Message* msg, - const upb_OneofDef* o) { - const upb_FieldDef* f = upb_OneofDef_Field(o, 0); - if (upb_OneofDef_IsSynthetic(o)) { - UPB_ASSERT(upb_OneofDef_FieldCount(o) == 1); - return upb_Message_Has(msg, f) ? f : NULL; - } else { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - uint32_t oneof_case = _upb_getoneofcase_field(msg, field); - f = oneof_case ? upb_OneofDef_LookupNumber(o, oneof_case) : NULL; - UPB_ASSERT((f != NULL) == (oneof_case != 0)); - return f; +static upb_tabent* emptyent(upb_table* t, upb_tabent* e) { + upb_tabent* begin = t->entries; + upb_tabent* end = begin + upb_table_size(t); + for (e = e + 1; e < end; e++) { + if (upb_tabent_isempty(e)) return e; + } + for (e = begin; e < end; e++) { + if (upb_tabent_isempty(e)) return e; } + UPB_ASSERT(false); + return NULL; } -upb_MessageValue upb_Message_Get(const upb_Message* msg, - const upb_FieldDef* f) { - if (upb_FieldDef_IsExtension(f)) { - const upb_Message_Extension* ext = - _upb_Message_Getext(msg, _upb_FieldDef_ExtensionMiniTable(f)); - if (ext) { - upb_MessageValue val; - memcpy(&val, &ext->data, sizeof(val)); - return val; - } else if (upb_FieldDef_IsRepeated(f)) { - return (upb_MessageValue){.array_val = NULL}; - } - } else if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) { - return _upb_Message_Getraw(msg, f); +static upb_tabent* getentry_mutable(upb_table* t, uint32_t hash) { + return (upb_tabent*)upb_getentry(t, hash); +} + +static const upb_tabent* findentry(const upb_table* t, lookupkey_t key, + uint32_t hash, eqlfunc_t* eql) { + const upb_tabent* e; + + if (t->size_lg2 == 0) return NULL; + e = upb_getentry(t, hash); + if (upb_tabent_isempty(e)) return NULL; + while (1) { + if (eql(e->key, key)) return e; + if ((e = e->next) == NULL) return NULL; } - return upb_FieldDef_Default(f); } -upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, - const upb_FieldDef* f, - upb_Arena* a) { - UPB_ASSERT(upb_FieldDef_IsSubMessage(f) || upb_FieldDef_IsRepeated(f)); - if (upb_FieldDef_HasPresence(f) && !upb_Message_Has(msg, f)) { - // We need to skip the upb_Message_Get() call in this case. - goto make; - } - - upb_MessageValue val = upb_Message_Get(msg, f); - if (val.array_val) { - return (upb_MutableMessageValue){.array = (upb_Array*)val.array_val}; - } +static upb_tabent* findentry_mutable(upb_table* t, lookupkey_t key, + uint32_t hash, eqlfunc_t* eql) { + return (upb_tabent*)findentry(t, key, hash, eql); +} - upb_MutableMessageValue ret; -make: - if (!a) return (upb_MutableMessageValue){.array = NULL}; - if (upb_FieldDef_IsMap(f)) { - const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); - const upb_FieldDef* key = - upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_KeyFieldNumber); - const upb_FieldDef* value = - upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_ValueFieldNumber); - ret.map = - upb_Map_New(a, upb_FieldDef_CType(key), upb_FieldDef_CType(value)); - } else if (upb_FieldDef_IsRepeated(f)) { - ret.array = upb_Array_New(a, upb_FieldDef_CType(f)); +static bool lookup(const upb_table* t, lookupkey_t key, upb_value* v, + uint32_t hash, eqlfunc_t* eql) { + const upb_tabent* e = findentry(t, key, hash, eql); + if (e) { + if (v) { + _upb_value_setval(v, e->val.val); + } + return true; } else { - UPB_ASSERT(upb_FieldDef_IsSubMessage(f)); - ret.msg = upb_Message_New(upb_FieldDef_MessageSubDef(f), a); + return false; } +} - val.array_val = ret.array; - upb_Message_Set(msg, f, val, a); +/* The given key must not already exist in the table. */ +static void insert(upb_table* t, lookupkey_t key, upb_tabkey tabkey, + upb_value val, uint32_t hash, hashfunc_t* hashfunc, + eqlfunc_t* eql) { + upb_tabent* mainpos_e; + upb_tabent* our_e; - return ret; -} + UPB_ASSERT(findentry(t, key, hash, eql) == NULL); -bool upb_Message_Set(upb_Message* msg, const upb_FieldDef* f, - upb_MessageValue val, upb_Arena* a) { - if (upb_FieldDef_IsExtension(f)) { - upb_Message_Extension* ext = _upb_Message_Getorcreateext( - msg, _upb_FieldDef_ExtensionMiniTable(f), a); - if (!ext) return false; - memcpy(&ext->data, &val, sizeof(val)); + t->count++; + mainpos_e = getentry_mutable(t, hash); + our_e = mainpos_e; + + if (upb_tabent_isempty(mainpos_e)) { + /* Our main position is empty; use it. */ + our_e->next = NULL; } else { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - char* mem = UPB_PTR_AT(msg, field->offset, char); - memcpy(mem, &val, get_field_size(field)); - if (field->presence > 0) { - _upb_sethas_field(msg, field); - } else if (in_oneof(field)) { - *_upb_oneofcase_field(msg, field) = field->number; + /* Collision. */ + upb_tabent* new_e = emptyent(t, mainpos_e); + /* Head of collider's chain. */ + upb_tabent* chain = getentry_mutable(t, hashfunc(mainpos_e->key)); + if (chain == mainpos_e) { + /* Existing ent is in its main position (it has the same hash as us, and + * is the head of our chain). Insert to new ent and append to this chain. + */ + new_e->next = mainpos_e->next; + mainpos_e->next = new_e; + our_e = new_e; + } else { + /* Existing ent is not in its main position (it is a node in some other + * chain). This implies that no existing ent in the table has our hash. + * Evict it (updating its chain) and use its ent for head of our chain. */ + *new_e = *mainpos_e; /* copies next. */ + while (chain->next != mainpos_e) { + chain = (upb_tabent*)chain->next; + UPB_ASSERT(chain); + } + chain->next = new_e; + our_e = mainpos_e; + our_e->next = NULL; } } - return true; + our_e->key = tabkey; + our_e->val.val = val.val; + UPB_ASSERT(findentry(t, key, hash, eql) == our_e); } -void upb_Message_ClearField(upb_Message* msg, const upb_FieldDef* f) { - if (upb_FieldDef_IsExtension(f)) { - _upb_Message_Clearext(msg, _upb_FieldDef_ExtensionMiniTable(f)); +static bool rm(upb_table* t, lookupkey_t key, upb_value* val, + upb_tabkey* removed, uint32_t hash, eqlfunc_t* eql) { + upb_tabent* chain = getentry_mutable(t, hash); + if (upb_tabent_isempty(chain)) return false; + if (eql(chain->key, key)) { + /* Element to remove is at the head of its chain. */ + t->count--; + if (val) _upb_value_setval(val, chain->val.val); + if (removed) *removed = chain->key; + if (chain->next) { + upb_tabent* move = (upb_tabent*)chain->next; + *chain = *move; + move->key = 0; /* Make the slot empty. */ + } else { + chain->key = 0; /* Make the slot empty. */ + } + return true; } else { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - char* mem = UPB_PTR_AT(msg, field->offset, char); - - if (field->presence > 0) { - _upb_clearhas_field(msg, field); - } else if (in_oneof(field)) { - uint32_t* oneof_case = _upb_oneofcase_field(msg, field); - if (*oneof_case != field->number) return; - *oneof_case = 0; + /* Element to remove is either in a non-head position or not in the + * table. */ + while (chain->next && !eql(chain->next->key, key)) { + chain = (upb_tabent*)chain->next; + } + if (chain->next) { + /* Found element to remove. */ + upb_tabent* rm = (upb_tabent*)chain->next; + t->count--; + if (val) _upb_value_setval(val, chain->next->val.val); + if (removed) *removed = rm->key; + rm->key = 0; /* Make the slot empty. */ + chain->next = rm->next; + return true; + } else { + /* Element to remove is not in the table. */ + return false; } - - memset(mem, 0, get_field_size(field)); } } -void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m) { - _upb_Message_Clear(msg, upb_MessageDef_MiniTable(m)); +static size_t next(const upb_table* t, size_t i) { + do { + if (++i >= upb_table_size(t)) return SIZE_MAX - 1; /* Distinct from -1. */ + } while (upb_tabent_isempty(&t->entries[i])); + + return i; } -bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, - const upb_DefPool* ext_pool, const upb_FieldDef** out_f, - upb_MessageValue* out_val, size_t* iter) { - size_t i = *iter; - size_t n = upb_MessageDef_FieldCount(m); - const upb_MessageValue zero = {0}; - UPB_UNUSED(ext_pool); +static size_t begin(const upb_table* t) { return next(t, -1); } - /* Iterate over normal fields, returning the first one that is set. */ - while (++i < n) { - const upb_FieldDef* f = upb_MessageDef_Field(m, i); - upb_MessageValue val = _upb_Message_Getraw(msg, f); +/* upb_strtable ***************************************************************/ - /* Skip field if unset or empty. */ - if (upb_FieldDef_HasPresence(f)) { - if (!upb_Message_Has(msg, f)) continue; - } else { - upb_MessageValue test = val; - if (upb_FieldDef_IsString(f) && !upb_FieldDef_IsRepeated(f)) { - /* Clear string pointer, only size matters (ptr could be non-NULL). */ - test.str_val.data = NULL; - } - /* Continue if NULL or 0. */ - if (memcmp(&test, &zero, sizeof(test)) == 0) continue; +/* A simple "subclass" of upb_table that only adds a hash function for strings. + */ - /* Continue on empty array or map. */ - if (upb_FieldDef_IsMap(f)) { - if (upb_Map_Size(test.map_val) == 0) continue; - } else if (upb_FieldDef_IsRepeated(f)) { - if (upb_Array_Size(test.array_val) == 0) continue; - } - } +static upb_tabkey strcopy(lookupkey_t k2, upb_Arena* a) { + uint32_t len = (uint32_t)k2.str.len; + char* str = upb_Arena_Malloc(a, k2.str.len + sizeof(uint32_t) + 1); + if (str == NULL) return 0; + memcpy(str, &len, sizeof(uint32_t)); + if (k2.str.len) memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len); + str[sizeof(uint32_t) + k2.str.len] = '\0'; + return (uintptr_t)str; +} - *out_val = val; - *out_f = f; - *iter = i; - return true; - } +/* Adapted from ABSL's wyhash. */ - if (ext_pool) { - /* Return any extensions that are set. */ - size_t count; - const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &count); - if (i - n < count) { - ext += count - 1 - (i - n); - memcpy(out_val, &ext->data, sizeof(*out_val)); - *out_f = _upb_DefPool_FindExtensionByMiniTable(ext_pool, ext->ext); - *iter = i; - return true; - } - } +static uint64_t UnalignedLoad64(const void* p) { + uint64_t val; + memcpy(&val, p, 8); + return val; +} + +static uint32_t UnalignedLoad32(const void* p) { + uint32_t val; + memcpy(&val, p, 4); + return val; +} + +#if defined(_MSC_VER) && defined(_M_X64) +#include +#endif + +/* Computes a * b, returning the low 64 bits of the result and storing the high + * 64 bits in |*high|. */ +static uint64_t upb_umul128(uint64_t v0, uint64_t v1, uint64_t* out_high) { +#ifdef __SIZEOF_INT128__ + __uint128_t p = v0; + p *= v1; + *out_high = (uint64_t)(p >> 64); + return (uint64_t)p; +#elif defined(_MSC_VER) && defined(_M_X64) + return _umul128(v0, v1, out_high); +#else + uint64_t a32 = v0 >> 32; + uint64_t a00 = v0 & 0xffffffff; + uint64_t b32 = v1 >> 32; + uint64_t b00 = v1 & 0xffffffff; + uint64_t high = a32 * b32; + uint64_t low = a00 * b00; + uint64_t mid1 = a32 * b00; + uint64_t mid2 = a00 * b32; + low += (mid1 << 32) + (mid2 << 32); + // Omit carry bit, for mixing we do not care about exact numerical precision. + high += (mid1 >> 32) + (mid2 >> 32); + *out_high = high; + return low; +#endif +} - *iter = i; - return false; +static uint64_t WyhashMix(uint64_t v0, uint64_t v1) { + uint64_t high; + uint64_t low = upb_umul128(v0, v1, &high); + return low ^ high; } -bool _upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, - int depth) { - size_t iter = kUpb_Message_Begin; - const upb_FieldDef* f; - upb_MessageValue val; - bool ret = true; +static uint64_t Wyhash(const void* data, size_t len, uint64_t seed, + const uint64_t salt[]) { + const uint8_t* ptr = (const uint8_t*)data; + uint64_t starting_length = (uint64_t)len; + uint64_t current_state = seed ^ salt[0]; - if (--depth == 0) return false; + if (len > 64) { + // If we have more than 64 bytes, we're going to handle chunks of 64 + // bytes at a time. We're going to build up two separate hash states + // which we will then hash together. + uint64_t duplicated_state = current_state; - _upb_Message_DiscardUnknown_shallow(msg); + do { + uint64_t a = UnalignedLoad64(ptr); + uint64_t b = UnalignedLoad64(ptr + 8); + uint64_t c = UnalignedLoad64(ptr + 16); + uint64_t d = UnalignedLoad64(ptr + 24); + uint64_t e = UnalignedLoad64(ptr + 32); + uint64_t f = UnalignedLoad64(ptr + 40); + uint64_t g = UnalignedLoad64(ptr + 48); + uint64_t h = UnalignedLoad64(ptr + 56); - while (upb_Message_Next(msg, m, NULL /*ext_pool*/, &f, &val, &iter)) { - const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); - if (!subm) continue; - if (upb_FieldDef_IsMap(f)) { - const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(subm, 2); - const upb_MessageDef* val_m = upb_FieldDef_MessageSubDef(val_f); - upb_Map* map = (upb_Map*)val.map_val; - size_t iter = kUpb_Map_Begin; + uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state); + uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state); + current_state = (cs0 ^ cs1); - if (!val_m) continue; + uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state); + uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state); + duplicated_state = (ds0 ^ ds1); - while (upb_MapIterator_Next(map, &iter)) { - upb_MessageValue map_val = upb_MapIterator_Value(map, iter); - if (!_upb_Message_DiscardUnknown((upb_Message*)map_val.msg_val, val_m, - depth)) { - ret = false; - } - } - } else if (upb_FieldDef_IsRepeated(f)) { - const upb_Array* arr = val.array_val; - size_t i, n = upb_Array_Size(arr); - for (i = 0; i < n; i++) { - upb_MessageValue elem = upb_Array_Get(arr, i); - if (!_upb_Message_DiscardUnknown((upb_Message*)elem.msg_val, subm, - depth)) { - ret = false; - } - } - } else { - if (!_upb_Message_DiscardUnknown((upb_Message*)val.msg_val, subm, - depth)) { - ret = false; - } - } - } + ptr += 64; + len -= 64; + } while (len > 64); - return ret; -} + current_state = current_state ^ duplicated_state; + } -bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, - int maxdepth) { - return _upb_Message_DiscardUnknown(msg, m, maxdepth); -} + // We now have a data `ptr` with at most 64 bytes and the current state + // of the hashing state machine stored in current_state. + while (len > 16) { + uint64_t a = UnalignedLoad64(ptr); + uint64_t b = UnalignedLoad64(ptr + 8); -/** upb_Array *****************************************************************/ + current_state = WyhashMix(a ^ salt[1], b ^ current_state); -upb_Array* upb_Array_New(upb_Arena* a, upb_CType type) { - return _upb_Array_New(a, 4, _upb_CTypeo_sizelg2[type]); -} + ptr += 16; + len -= 16; + } -size_t upb_Array_Size(const upb_Array* arr) { return arr->len; } + // We now have a data `ptr` with at most 16 bytes. + uint64_t a = 0; + uint64_t b = 0; + if (len > 8) { + // When we have at least 9 and at most 16 bytes, set A to the first 64 + // bits of the input and B to the last 64 bits of the input. Yes, they will + // overlap in the middle if we are working with less than the full 16 + // bytes. + a = UnalignedLoad64(ptr); + b = UnalignedLoad64(ptr + len - 8); + } else if (len > 3) { + // If we have at least 4 and at most 8 bytes, set A to the first 32 + // bits and B to the last 32 bits. + a = UnalignedLoad32(ptr); + b = UnalignedLoad32(ptr + len - 4); + } else if (len > 0) { + // If we have at least 1 and at most 3 bytes, read all of the provided + // bits into A, with some adjustments. + a = ((ptr[0] << 16) | (ptr[len >> 1] << 8) | ptr[len - 1]); + b = 0; + } else { + a = 0; + b = 0; + } -upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i) { - upb_MessageValue ret; - const char* data = _upb_array_constptr(arr); - int lg2 = arr->data & 7; - UPB_ASSERT(i < arr->len); - memcpy(&ret, data + (i << lg2), 1 << lg2); - return ret; + uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state); + uint64_t z = salt[1] ^ starting_length; + return WyhashMix(w, z); } -void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) { - char* data = _upb_array_ptr(arr); - int lg2 = arr->data & 7; - UPB_ASSERT(i < arr->len); - memcpy(data + (i << lg2), &val, 1 << lg2); -} +const uint64_t kWyhashSalt[5] = { + 0x243F6A8885A308D3ULL, 0x13198A2E03707344ULL, 0xA4093822299F31D0ULL, + 0x082EFA98EC4E6C89ULL, 0x452821E638D01377ULL, +}; -bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) { - if (!upb_Array_Resize(arr, arr->len + 1, arena)) { - return false; - } - upb_Array_Set(arr, arr->len - 1, val); - return true; +uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed) { + return Wyhash(p, n, seed, kWyhashSalt); } -void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx, - size_t count) { - char* data = _upb_array_ptr(arr); - int lg2 = arr->data & 7; - memmove(&data[dst_idx << lg2], &data[src_idx << lg2], count << lg2); +static uint32_t _upb_Hash_NoSeed(const char* p, size_t n) { + return _upb_Hash(p, n, 0); } -bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count, - upb_Arena* arena) { - UPB_ASSERT(i <= arr->len); - UPB_ASSERT(count + arr->len >= count); - size_t oldsize = arr->len; - if (!upb_Array_Resize(arr, arr->len + count, arena)) { - return false; - } - upb_Array_Move(arr, i + count, i, oldsize - i); - return true; +static uint32_t strhash(upb_tabkey key) { + uint32_t len; + char* str = upb_tabstr(key, &len); + return _upb_Hash_NoSeed(str, len); } -/* - * i end arr->len - * |------------|XXXXXXXX|--------| - */ -void upb_Array_Delete(upb_Array* arr, size_t i, size_t count) { - size_t end = i + count; - UPB_ASSERT(i <= end); - UPB_ASSERT(end <= arr->len); - upb_Array_Move(arr, i, end, arr->len - end); - arr->len -= count; +static bool streql(upb_tabkey k1, lookupkey_t k2) { + uint32_t len; + char* str = upb_tabstr(k1, &len); + return len == k2.str.len && (len == 0 || memcmp(str, k2.str.str, len) == 0); } -bool upb_Array_Resize(upb_Array* arr, size_t size, upb_Arena* arena) { - return _upb_Array_Resize(arr, size, arena); +bool upb_strtable_init(upb_strtable* t, size_t expected_size, upb_Arena* a) { + // Multiply by approximate reciprocal of MAX_LOAD (0.85), with pow2 + // denominator. + size_t need_entries = (expected_size + 1) * 1204 / 1024; + UPB_ASSERT(need_entries >= expected_size * 0.85); + int size_lg2 = _upb_Log2Ceiling(need_entries); + return init(&t->t, size_lg2, a); } -/** upb_Map *******************************************************************/ - -upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type) { - return _upb_Map_New(a, _upb_CTypeo_mapsize[key_type], - _upb_CTypeo_mapsize[value_type]); +void upb_strtable_clear(upb_strtable* t) { + size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent); + t->t.count = 0; + memset((char*)t->t.entries, 0, bytes); } -size_t upb_Map_Size(const upb_Map* map) { return _upb_Map_Size(map); } +bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a) { + upb_strtable new_table; + upb_strtable_iter i; -bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, - upb_MessageValue* val) { - return _upb_Map_Get(map, &key, map->key_size, val, map->val_size); + if (!init(&new_table.t, size_lg2, a)) return false; + upb_strtable_begin(&i, t); + for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { + upb_StringView key = upb_strtable_iter_key(&i); + upb_strtable_insert(&new_table, key.data, key.size, + upb_strtable_iter_value(&i), a); + } + *t = new_table; + return true; } -void upb_Map_Clear(upb_Map* map) { _upb_Map_Clear(map); } +bool upb_strtable_insert(upb_strtable* t, const char* k, size_t len, + upb_value v, upb_Arena* a) { + lookupkey_t key; + upb_tabkey tabkey; + uint32_t hash; -bool upb_Map_Set(upb_Map* map, upb_MessageValue key, upb_MessageValue val, - upb_Arena* arena) { - return _upb_Map_Set(map, &key, map->key_size, &val, map->val_size, arena); -} + if (isfull(&t->t)) { + /* Need to resize. New table of double the size, add old elements to it. */ + if (!upb_strtable_resize(t, t->t.size_lg2 + 1, a)) { + return false; + } + } -bool upb_Map_Delete(upb_Map* map, upb_MessageValue key) { - return _upb_Map_Delete(map, &key, map->key_size); + key = strkey2(k, len); + tabkey = strcopy(key, a); + if (tabkey == 0) return false; + + hash = _upb_Hash_NoSeed(key.str.str, key.str.len); + insert(&t->t, key, tabkey, v, hash, &strhash, &streql); + return true; } -bool upb_MapIterator_Next(const upb_Map* map, size_t* iter) { - return _upb_map_next(map, iter); +bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, + upb_value* v) { + uint32_t hash = _upb_Hash_NoSeed(key, len); + return lookup(&t->t, strkey2(key, len), v, hash, &streql); } -bool upb_MapIterator_Done(const upb_Map* map, size_t iter) { - upb_strtable_iter i; - UPB_ASSERT(iter != kUpb_Map_Begin); - i.t = &map->table; - i.index = iter; - return upb_strtable_done(&i); +bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, + upb_value* val) { + uint32_t hash = _upb_Hash_NoSeed(key, len); + upb_tabkey tabkey; + return rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql); } -/* Returns the key and value for this entry of the map. */ -upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter) { - upb_strtable_iter i; - upb_MessageValue ret; - i.t = &map->table; - i.index = iter; - _upb_map_fromkey(upb_strtable_iter_key(&i), &ret, map->key_size); - return ret; +/* Iteration */ + +void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t) { + i->t = t; + i->index = begin(&t->t); } -upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter) { - upb_strtable_iter i; - upb_MessageValue ret; - i.t = &map->table; - i.index = iter; - _upb_map_fromvalue(upb_strtable_iter_value(&i), &ret, map->val_size); - return ret; +void upb_strtable_next(upb_strtable_iter* i) { + i->index = next(&i->t->t, i->index); } -/* void upb_MapIterator_SetValue(upb_Map *map, size_t iter, upb_MessageValue - * value); */ +bool upb_strtable_done(const upb_strtable_iter* i) { + if (!i->t) return true; + return i->index >= upb_table_size(&i->t->t) || + upb_tabent_isempty(str_tabent(i)); +} -/** upb/json_decode.c ************************************************************/ +upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i) { + upb_StringView key; + uint32_t len; + UPB_ASSERT(!upb_strtable_done(i)); + key.data = upb_tabstr(str_tabent(i)->key, &len); + key.size = len; + return key; +} -#include -#include -#include -#include -#include -#include -#include -#include +upb_value upb_strtable_iter_value(const upb_strtable_iter* i) { + UPB_ASSERT(!upb_strtable_done(i)); + return _upb_value_val(str_tabent(i)->val.val); +} +void upb_strtable_iter_setdone(upb_strtable_iter* i) { + i->t = NULL; + i->index = SIZE_MAX; +} -/* Special header, must be included last. */ +bool upb_strtable_iter_isequal(const upb_strtable_iter* i1, + const upb_strtable_iter* i2) { + if (upb_strtable_done(i1) && upb_strtable_done(i2)) return true; + return i1->t == i2->t && i1->index == i2->index; +} -typedef struct { - const char *ptr, *end; - upb_Arena* arena; /* TODO: should we have a tmp arena for tmp data? */ - const upb_DefPool* symtab; - int depth; - upb_Status* status; - jmp_buf err; - int line; - const char* line_begin; - bool is_first; - int options; - const upb_FieldDef* debug_field; -} jsondec; +/* upb_inttable ***************************************************************/ -enum { JD_OBJECT, JD_ARRAY, JD_STRING, JD_NUMBER, JD_TRUE, JD_FALSE, JD_NULL }; +/* For inttables we use a hybrid structure where small keys are kept in an + * array and large keys are put in the hash table. */ -/* Forward declarations of mutually-recursive functions. */ -static void jsondec_wellknown(jsondec* d, upb_Message* msg, - const upb_MessageDef* m); -static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f); -static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, - const upb_MessageDef* m); -static void jsondec_object(jsondec* d, upb_Message* msg, - const upb_MessageDef* m); +static uint32_t inthash(upb_tabkey key) { return upb_inthash(key); } -static bool jsondec_streql(upb_StringView str, const char* lit) { - return str.size == strlen(lit) && memcmp(str.data, lit, str.size) == 0; -} +static bool inteql(upb_tabkey k1, lookupkey_t k2) { return k1 == k2.num; } -static bool jsondec_isnullvalue(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Enum && - strcmp(upb_EnumDef_FullName(upb_FieldDef_EnumSubDef(f)), - "google.protobuf.NullValue") == 0; +static upb_tabval* mutable_array(upb_inttable* t) { + return (upb_tabval*)t->array; } -static bool jsondec_isvalue(const upb_FieldDef* f) { - return (upb_FieldDef_CType(f) == kUpb_CType_Message && - upb_MessageDef_WellKnownType(upb_FieldDef_MessageSubDef(f)) == - kUpb_WellKnown_Value) || - jsondec_isnullvalue(f); +static upb_tabval* inttable_val(upb_inttable* t, uintptr_t key) { + if (key < t->array_size) { + return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL; + } else { + upb_tabent* e = + findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql); + return e ? &e->val : NULL; + } } -UPB_NORETURN static void jsondec_err(jsondec* d, const char* msg) { - upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: %s", d->line, - (int)(d->ptr - d->line_begin), msg); - UPB_LONGJMP(d->err, 1); +static const upb_tabval* inttable_val_const(const upb_inttable* t, + uintptr_t key) { + return inttable_val((upb_inttable*)t, key); } -UPB_PRINTF(2, 3) -UPB_NORETURN static void jsondec_errf(jsondec* d, const char* fmt, ...) { - va_list argp; - upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: ", d->line, - (int)(d->ptr - d->line_begin)); - va_start(argp, fmt); - upb_Status_VAppendErrorFormat(d->status, fmt, argp); - va_end(argp); - UPB_LONGJMP(d->err, 1); +size_t upb_inttable_count(const upb_inttable* t) { + return t->t.count + t->array_count; } -static void jsondec_skipws(jsondec* d) { - while (d->ptr != d->end) { - switch (*d->ptr) { - case '\n': - d->line++; - d->line_begin = d->ptr; - /* Fallthrough. */ - case '\r': - case '\t': - case ' ': - d->ptr++; - break; - default: - return; +static void check(upb_inttable* t) { + UPB_UNUSED(t); +#if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG) + { + /* This check is very expensive (makes inserts/deletes O(N)). */ + size_t count = 0; + upb_inttable_iter i; + upb_inttable_begin(&i, t); + for (; !upb_inttable_done(&i); upb_inttable_next(&i), count++) { + UPB_ASSERT(upb_inttable_lookup(t, upb_inttable_iter_key(&i), NULL)); } + UPB_ASSERT(count == upb_inttable_count(t)); } - jsondec_err(d, "Unexpected EOF"); +#endif } -static bool jsondec_tryparsech(jsondec* d, char ch) { - if (d->ptr == d->end || *d->ptr != ch) return false; - d->ptr++; - return true; -} +bool upb_inttable_sizedinit(upb_inttable* t, size_t asize, int hsize_lg2, + upb_Arena* a) { + size_t array_bytes; -static void jsondec_parselit(jsondec* d, const char* lit) { - size_t avail = d->end - d->ptr; - size_t len = strlen(lit); - if (avail < len || memcmp(d->ptr, lit, len) != 0) { - jsondec_errf(d, "Expected: '%s'", lit); + if (!init(&t->t, hsize_lg2, a)) return false; + /* Always make the array part at least 1 long, so that we know key 0 + * won't be in the hash part, which simplifies things. */ + t->array_size = UPB_MAX(1, asize); + t->array_count = 0; + array_bytes = t->array_size * sizeof(upb_value); + t->array = upb_Arena_Malloc(a, array_bytes); + if (!t->array) { + return false; } - d->ptr += len; + memset(mutable_array(t), 0xff, array_bytes); + check(t); + return true; } -static void jsondec_wsch(jsondec* d, char ch) { - jsondec_skipws(d); - if (!jsondec_tryparsech(d, ch)) { - jsondec_errf(d, "Expected: '%c'", ch); - } +bool upb_inttable_init(upb_inttable* t, upb_Arena* a) { + return upb_inttable_sizedinit(t, 0, 4, a); } -static void jsondec_true(jsondec* d) { jsondec_parselit(d, "true"); } -static void jsondec_false(jsondec* d) { jsondec_parselit(d, "false"); } -static void jsondec_null(jsondec* d) { jsondec_parselit(d, "null"); } +bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, + upb_Arena* a) { + upb_tabval tabval; + tabval.val = val.val; + UPB_ASSERT( + upb_arrhas(tabval)); /* This will reject (uint64_t)-1. Fix this. */ -static void jsondec_entrysep(jsondec* d) { - jsondec_skipws(d); - jsondec_parselit(d, ":"); -} + if (key < t->array_size) { + UPB_ASSERT(!upb_arrhas(t->array[key])); + t->array_count++; + mutable_array(t)[key].val = val.val; + } else { + if (isfull(&t->t)) { + /* Need to resize the hash part, but we re-use the array part. */ + size_t i; + upb_table new_table; -static int jsondec_rawpeek(jsondec* d) { - switch (*d->ptr) { - case '{': - return JD_OBJECT; - case '[': - return JD_ARRAY; - case '"': - return JD_STRING; - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return JD_NUMBER; - case 't': - return JD_TRUE; - case 'f': - return JD_FALSE; - case 'n': - return JD_NULL; - default: - jsondec_errf(d, "Unexpected character: '%c'", *d->ptr); - } -} + if (!init(&new_table, t->t.size_lg2 + 1, a)) { + return false; + } -/* JSON object/array **********************************************************/ + for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) { + const upb_tabent* e = &t->t.entries[i]; + uint32_t hash; + upb_value v; -/* These are used like so: - * - * jsondec_objstart(d); - * while (jsondec_objnext(d)) { - * ... - * } - * jsondec_objend(d) */ + _upb_value_setval(&v, e->val.val); + hash = upb_inthash(e->key); + insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql); + } -static int jsondec_peek(jsondec* d) { - jsondec_skipws(d); - return jsondec_rawpeek(d); -} + UPB_ASSERT(t->t.count == new_table.count); -static void jsondec_push(jsondec* d) { - if (--d->depth < 0) { - jsondec_err(d, "Recursion limit exceeded"); + t->t = new_table; + } + insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql); } - d->is_first = true; + check(t); + return true; } -static bool jsondec_seqnext(jsondec* d, char end_ch) { - bool is_first = d->is_first; - d->is_first = false; - jsondec_skipws(d); - if (*d->ptr == end_ch) return false; - if (!is_first) jsondec_parselit(d, ","); +bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v) { + const upb_tabval* table_v = inttable_val_const(t, key); + if (!table_v) return false; + if (v) _upb_value_setval(v, table_v->val); return true; } -static void jsondec_arrstart(jsondec* d) { - jsondec_push(d); - jsondec_wsch(d, '['); +bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val) { + upb_tabval* table_v = inttable_val(t, key); + if (!table_v) return false; + table_v->val = val.val; + return true; } -static void jsondec_arrend(jsondec* d) { - d->depth++; - jsondec_wsch(d, ']'); +bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val) { + bool success; + if (key < t->array_size) { + if (upb_arrhas(t->array[key])) { + upb_tabval empty = UPB_TABVALUE_EMPTY_INIT; + t->array_count--; + if (val) { + _upb_value_setval(val, t->array[key].val); + } + mutable_array(t)[key] = empty; + success = true; + } else { + success = false; + } + } else { + success = rm(&t->t, intkey(key), val, NULL, upb_inthash(key), &inteql); + } + check(t); + return success; } -static bool jsondec_arrnext(jsondec* d) { return jsondec_seqnext(d, ']'); } +void upb_inttable_compact(upb_inttable* t, upb_Arena* a) { + /* A power-of-two histogram of the table keys. */ + size_t counts[UPB_MAXARRSIZE + 1] = {0}; -static void jsondec_objstart(jsondec* d) { - jsondec_push(d); - jsondec_wsch(d, '{'); -} + /* The max key in each bucket. */ + uintptr_t max[UPB_MAXARRSIZE + 1] = {0}; -static void jsondec_objend(jsondec* d) { - d->depth++; - jsondec_wsch(d, '}'); -} + upb_inttable_iter i; + size_t arr_count; + int size_lg2; + upb_inttable new_t; -static bool jsondec_objnext(jsondec* d) { - if (!jsondec_seqnext(d, '}')) return false; - if (jsondec_peek(d) != JD_STRING) { - jsondec_err(d, "Object must start with string"); + upb_inttable_begin(&i, t); + for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { + uintptr_t key = upb_inttable_iter_key(&i); + int bucket = log2ceil(key); + max[bucket] = UPB_MAX(max[bucket], key); + counts[bucket]++; } - return true; -} -/* JSON number ****************************************************************/ - -static bool jsondec_tryskipdigits(jsondec* d) { - const char* start = d->ptr; + /* Find the largest power of two that satisfies the MIN_DENSITY + * definition (while actually having some keys). */ + arr_count = upb_inttable_count(t); - while (d->ptr < d->end) { - if (*d->ptr < '0' || *d->ptr > '9') { + for (size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 0; size_lg2--) { + if (counts[size_lg2] == 0) { + /* We can halve again without losing any entries. */ + continue; + } else if (arr_count >= (1 << size_lg2) * MIN_DENSITY) { break; } - d->ptr++; + + arr_count -= counts[size_lg2]; } - return d->ptr != start; -} + UPB_ASSERT(arr_count <= upb_inttable_count(t)); -static void jsondec_skipdigits(jsondec* d) { - if (!jsondec_tryskipdigits(d)) { - jsondec_err(d, "Expected one or more digits"); + { + /* Insert all elements into new, perfectly-sized table. */ + size_t arr_size = max[size_lg2] + 1; /* +1 so arr[max] will fit. */ + size_t hash_count = upb_inttable_count(t) - arr_count; + size_t hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0; + int hashsize_lg2 = log2ceil(hash_size); + + upb_inttable_sizedinit(&new_t, arr_size, hashsize_lg2, a); + upb_inttable_begin(&i, t); + for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { + uintptr_t k = upb_inttable_iter_key(&i); + upb_inttable_insert(&new_t, k, upb_inttable_iter_value(&i), a); + } + UPB_ASSERT(new_t.array_size == arr_size); + UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2); } + *t = new_t; } -static double jsondec_number(jsondec* d) { - const char* start = d->ptr; +/* Iteration. */ - assert(jsondec_rawpeek(d) == JD_NUMBER); +static const upb_tabent* int_tabent(const upb_inttable_iter* i) { + UPB_ASSERT(!i->array_part); + return &i->t->t.entries[i->index]; +} - /* Skip over the syntax of a number, as specified by JSON. */ - if (*d->ptr == '-') d->ptr++; +static upb_tabval int_arrent(const upb_inttable_iter* i) { + UPB_ASSERT(i->array_part); + return i->t->array[i->index]; +} - if (jsondec_tryparsech(d, '0')) { - if (jsondec_tryskipdigits(d)) { - jsondec_err(d, "number cannot have leading zero"); +void upb_inttable_begin(upb_inttable_iter* i, const upb_inttable* t) { + i->t = t; + i->index = -1; + i->array_part = true; + upb_inttable_next(i); +} + +void upb_inttable_next(upb_inttable_iter* iter) { + const upb_inttable* t = iter->t; + if (iter->array_part) { + while (++iter->index < t->array_size) { + if (upb_arrhas(int_arrent(iter))) { + return; + } } + iter->array_part = false; + iter->index = begin(&t->t); } else { - jsondec_skipdigits(d); + iter->index = next(&t->t, iter->index); } +} - if (d->ptr == d->end) goto parse; - if (jsondec_tryparsech(d, '.')) { - jsondec_skipdigits(d); +bool upb_inttable_next2(const upb_inttable* t, uintptr_t* key, upb_value* val, + intptr_t* iter) { + intptr_t i = *iter; + if (i < t->array_size) { + while (++i < t->array_size) { + upb_tabval ent = t->array[i]; + if (upb_arrhas(ent)) { + *key = i; + *val = _upb_value_val(ent.val); + *iter = i; + return true; + } + } } - if (d->ptr == d->end) goto parse; - if (*d->ptr == 'e' || *d->ptr == 'E') { - d->ptr++; - if (d->ptr == d->end) { - jsondec_err(d, "Unexpected EOF in number"); - } - if (*d->ptr == '+' || *d->ptr == '-') { - d->ptr++; - } - jsondec_skipdigits(d); + size_t tab_idx = next(&t->t, i == -1 ? -1 : i - t->array_size); + if (tab_idx < upb_table_size(&t->t)) { + upb_tabent* ent = &t->t.entries[tab_idx]; + *key = ent->key; + *val = _upb_value_val(ent->val.val); + *iter = tab_idx + t->array_size; + return true; } -parse: - /* Having verified the syntax of a JSON number, use strtod() to parse - * (strtod() accepts a superset of JSON syntax). */ - errno = 0; - { - char* end; - double val = strtod(start, &end); - assert(end == d->ptr); + return false; +} - /* Currently the min/max-val conformance tests fail if we check this. Does - * this mean the conformance tests are wrong or strtod() is wrong, or - * something else? Investigate further. */ - /* - if (errno == ERANGE) { - jsondec_err(d, "Number out of range"); +void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter) { + intptr_t i = *iter; + if (i < t->array_size) { + t->array_count--; + mutable_array(t)[i].val = -1; + } else { + upb_tabent* ent = &t->t.entries[i - t->array_size]; + upb_tabent* prev = NULL; + + // Linear search, not great. + upb_tabent* end = &t->t.entries[upb_table_size(&t->t)]; + for (upb_tabent* e = t->t.entries; e != end; e++) { + if (e->next == ent) { + prev = e; + break; + } } - */ - if (val > DBL_MAX || val < -DBL_MAX) { - jsondec_err(d, "Number out of range"); + if (prev) { + prev->next = ent->next; } - return val; + t->t.count--; + ent->key = 0; + ent->next = NULL; } } -/* JSON string ****************************************************************/ - -static char jsondec_escape(jsondec* d) { - switch (*d->ptr++) { - case '"': - return '\"'; - case '\\': - return '\\'; - case '/': - return '/'; - case 'b': - return '\b'; - case 'f': - return '\f'; - case 'n': - return '\n'; - case 'r': - return '\r'; - case 't': - return '\t'; - default: - jsondec_err(d, "Invalid escape char"); +bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key, + upb_value* val, intptr_t* iter) { + size_t tab_idx = next(&t->t, *iter); + if (tab_idx < upb_table_size(&t->t)) { + upb_tabent* ent = &t->t.entries[tab_idx]; + uint32_t len; + key->data = upb_tabstr(ent->key, &len); + key->size = len; + *val = _upb_value_val(ent->val.val); + *iter = tab_idx; + return true; } + + return false; } -static uint32_t jsondec_codepoint(jsondec* d) { - uint32_t cp = 0; - const char* end; +void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter) { + intptr_t i = *iter; + upb_tabent* ent = &t->t.entries[i]; + upb_tabent* prev = NULL; - if (d->end - d->ptr < 4) { - jsondec_err(d, "EOF inside string"); + // Linear search, not great. + upb_tabent* end = &t->t.entries[upb_table_size(&t->t)]; + for (upb_tabent* e = t->t.entries; e != end; e++) { + if (e->next == ent) { + prev = e; + break; + } } - end = d->ptr + 4; - while (d->ptr < end) { - char ch = *d->ptr++; - if (ch >= '0' && ch <= '9') { - ch -= '0'; - } else if (ch >= 'a' && ch <= 'f') { - ch = ch - 'a' + 10; - } else if (ch >= 'A' && ch <= 'F') { - ch = ch - 'A' + 10; - } else { - jsondec_err(d, "Invalid hex digit"); - } - cp = (cp << 4) | ch; + if (prev) { + prev->next = ent->next; } - return cp; + t->t.count--; + ent->key = 0; + ent->next = NULL; } -/* Parses a \uXXXX unicode escape (possibly a surrogate pair). */ -static size_t jsondec_unicode(jsondec* d, char* out) { - uint32_t cp = jsondec_codepoint(d); - if (cp >= 0xd800 && cp <= 0xdbff) { - /* Surrogate pair: two 16-bit codepoints become a 32-bit codepoint. */ - uint32_t high = cp; - uint32_t low; - jsondec_parselit(d, "\\u"); - low = jsondec_codepoint(d); - if (low < 0xdc00 || low > 0xdfff) { - jsondec_err(d, "Invalid low surrogate"); - } - cp = (high & 0x3ff) << 10; - cp |= (low & 0x3ff); - cp += 0x10000; - } else if (cp >= 0xdc00 && cp <= 0xdfff) { - jsondec_err(d, "Unpaired low surrogate"); +bool upb_inttable_done(const upb_inttable_iter* i) { + if (!i->t) return true; + if (i->array_part) { + return i->index >= i->t->array_size || !upb_arrhas(int_arrent(i)); + } else { + return i->index >= upb_table_size(&i->t->t) || + upb_tabent_isempty(int_tabent(i)); } +} - /* Write to UTF-8 */ +uintptr_t upb_inttable_iter_key(const upb_inttable_iter* i) { + UPB_ASSERT(!upb_inttable_done(i)); + return i->array_part ? i->index : int_tabent(i)->key; +} + +upb_value upb_inttable_iter_value(const upb_inttable_iter* i) { + UPB_ASSERT(!upb_inttable_done(i)); + return _upb_value_val(i->array_part ? i->t->array[i->index].val + : int_tabent(i)->val.val); +} + +void upb_inttable_iter_setdone(upb_inttable_iter* i) { + i->t = NULL; + i->index = SIZE_MAX; + i->array_part = false; +} + +bool upb_inttable_iter_isequal(const upb_inttable_iter* i1, + const upb_inttable_iter* i2) { + if (upb_inttable_done(i1) && upb_inttable_done(i2)) return true; + return i1->t == i2->t && i1->index == i2->index && + i1->array_part == i2->array_part; +} + + +// Must be last. + +int upb_Unicode_ToUTF8(uint32_t cp, char* out) { if (cp <= 0x7f) { out[0] = cp; return 1; - } else if (cp <= 0x07FF) { - out[0] = ((cp >> 6) & 0x1F) | 0xC0; - out[1] = ((cp >> 0) & 0x3F) | 0x80; + } + if (cp <= 0x07ff) { + out[0] = (cp >> 6) | 0xc0; + out[1] = (cp & 0x3f) | 0x80; return 2; - } else if (cp <= 0xFFFF) { - out[0] = ((cp >> 12) & 0x0F) | 0xE0; - out[1] = ((cp >> 6) & 0x3F) | 0x80; - out[2] = ((cp >> 0) & 0x3F) | 0x80; + } + if (cp <= 0xffff) { + out[0] = (cp >> 12) | 0xe0; + out[1] = ((cp >> 6) & 0x3f) | 0x80; + out[2] = (cp & 0x3f) | 0x80; return 3; - } else if (cp < 0x10FFFF) { - out[0] = ((cp >> 18) & 0x07) | 0xF0; + } + if (cp <= 0x10ffff) { + out[0] = (cp >> 18) | 0xf0; out[1] = ((cp >> 12) & 0x3f) | 0x80; out[2] = ((cp >> 6) & 0x3f) | 0x80; - out[3] = ((cp >> 0) & 0x3f) | 0x80; + out[3] = (cp & 0x3f) | 0x80; return 4; + } + return 0; +} + + +#include + +// Must be last. + +static void* upb_global_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize, + size_t size) { + UPB_UNUSED(alloc); + UPB_UNUSED(oldsize); + if (size == 0) { + free(ptr); + return NULL; } else { - jsondec_err(d, "Invalid codepoint"); + return realloc(ptr, size); } } -static void jsondec_resize(jsondec* d, char** buf, char** end, char** buf_end) { - size_t oldsize = *buf_end - *buf; - size_t len = *end - *buf; - size_t size = UPB_MAX(8, 2 * oldsize); +upb_alloc upb_alloc_global = {&upb_global_allocfunc}; - *buf = upb_Arena_Realloc(d->arena, *buf, len, size); - if (!*buf) jsondec_err(d, "Out of memory"); - *end = *buf + len; - *buf_end = *buf + size; +// Must be last. + +static uint32_t* upb_cleanup_pointer(uintptr_t cleanup_metadata) { + return (uint32_t*)(cleanup_metadata & ~0x1); } -static upb_StringView jsondec_string(jsondec* d) { - char* buf = NULL; - char* end = NULL; - char* buf_end = NULL; +static bool upb_cleanup_has_initial_block(uintptr_t cleanup_metadata) { + return cleanup_metadata & 0x1; +} - jsondec_skipws(d); +static uintptr_t upb_cleanup_metadata(uint32_t* cleanup, + bool has_initial_block) { + return (uintptr_t)cleanup | has_initial_block; +} - if (*d->ptr++ != '"') { - jsondec_err(d, "Expected string"); +struct mem_block { + struct mem_block* next; + uint32_t size; + uint32_t cleanups; + /* Data follows. */ +}; + +typedef struct cleanup_ent { + upb_CleanupFunc* cleanup; + void* ud; +} cleanup_ent; + +static const size_t memblock_reserve = + UPB_ALIGN_UP(sizeof(mem_block), UPB_MALLOC_ALIGN); + +static upb_Arena* arena_findroot(upb_Arena* a) { + /* Path splitting keeps time complexity down, see: + * https://en.wikipedia.org/wiki/Disjoint-set_data_structure */ + while (a->parent != a) { + upb_Arena* next = a->parent; + a->parent = next->parent; + a = next; } + return a; +} - while (d->ptr < d->end) { - char ch = *d->ptr++; +size_t upb_Arena_SpaceAllocated(upb_Arena* arena) { + arena = arena_findroot(arena); + size_t memsize = 0; - if (end == buf_end) { - jsondec_resize(d, &buf, &end, &buf_end); - } + mem_block* block = arena->freelist; - switch (ch) { - case '"': { - upb_StringView ret; - ret.data = buf; - ret.size = end - buf; - *end = '\0'; /* Needed for possible strtod(). */ - return ret; - } - case '\\': - if (d->ptr == d->end) goto eof; - if (*d->ptr == 'u') { - d->ptr++; - if (buf_end - end < 4) { - /* Allow space for maximum-sized code point (4 bytes). */ - jsondec_resize(d, &buf, &end, &buf_end); - } - end += jsondec_unicode(d, end); - } else { - *end++ = jsondec_escape(d); - } - break; - default: - if ((unsigned char)*d->ptr < 0x20) { - jsondec_err(d, "Invalid char in JSON string"); - } - *end++ = ch; - break; - } + while (block) { + memsize += sizeof(mem_block) + block->size; + block = block->next; } -eof: - jsondec_err(d, "EOF inside string"); + return memsize; } -static void jsondec_skipval(jsondec* d) { - switch (jsondec_peek(d)) { - case JD_OBJECT: - jsondec_objstart(d); - while (jsondec_objnext(d)) { - jsondec_string(d); - jsondec_entrysep(d); - jsondec_skipval(d); - } - jsondec_objend(d); - break; - case JD_ARRAY: - jsondec_arrstart(d); - while (jsondec_arrnext(d)) { - jsondec_skipval(d); - } - jsondec_arrend(d); - break; - case JD_TRUE: - jsondec_true(d); - break; - case JD_FALSE: - jsondec_false(d); - break; - case JD_NULL: - jsondec_null(d); - break; - case JD_STRING: - jsondec_string(d); - break; - case JD_NUMBER: - jsondec_number(d); - break; - } +uint32_t upb_Arena_DebugRefCount(upb_Arena* arena) { + return arena_findroot(arena)->refcount; +} + +static void upb_Arena_addblock(upb_Arena* a, upb_Arena* root, void* ptr, + size_t size) { + mem_block* block = ptr; + + /* The block is for arena |a|, but should appear in the freelist of |root|. */ + block->next = root->freelist; + block->size = (uint32_t)size; + block->cleanups = 0; + root->freelist = block; + a->last_size = block->size; + if (!root->freelist_tail) root->freelist_tail = block; + + a->head.ptr = UPB_PTR_AT(block, memblock_reserve, char); + a->head.end = UPB_PTR_AT(block, size, char); + a->cleanup_metadata = upb_cleanup_metadata( + &block->cleanups, upb_cleanup_has_initial_block(a->cleanup_metadata)); + + UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr); +} + +static bool upb_Arena_Allocblock(upb_Arena* a, size_t size) { + upb_Arena* root = arena_findroot(a); + size_t block_size = UPB_MAX(size, a->last_size * 2) + memblock_reserve; + mem_block* block = upb_malloc(root->block_alloc, block_size); + + if (!block) return false; + upb_Arena_addblock(a, root, block, block_size); + return true; +} + +void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size) { + if (!upb_Arena_Allocblock(a, size)) return NULL; /* Out of memory. */ + UPB_ASSERT(_upb_ArenaHas(a) >= size); + return upb_Arena_Malloc(a, size); +} + +static void* upb_Arena_doalloc(upb_alloc* alloc, void* ptr, size_t oldsize, + size_t size) { + upb_Arena* a = (upb_Arena*)alloc; /* upb_alloc is initial member. */ + return upb_Arena_Realloc(a, ptr, oldsize, size); } -/* Base64 decoding for bytes fields. ******************************************/ +/* Public Arena API ***********************************************************/ -static unsigned int jsondec_base64_tablelookup(const char ch) { - /* Table includes the normal base64 chars plus the URL-safe variant. */ - const signed char table[256] = { - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, 62 /*+*/, -1, 62 /*-*/, -1, 63 /*/ */, 52 /*0*/, - 53 /*1*/, 54 /*2*/, 55 /*3*/, 56 /*4*/, 57 /*5*/, 58 /*6*/, 59 /*7*/, - 60 /*8*/, 61 /*9*/, -1, -1, -1, -1, -1, - -1, -1, 0 /*A*/, 1 /*B*/, 2 /*C*/, 3 /*D*/, 4 /*E*/, - 5 /*F*/, 6 /*G*/, 07 /*H*/, 8 /*I*/, 9 /*J*/, 10 /*K*/, 11 /*L*/, - 12 /*M*/, 13 /*N*/, 14 /*O*/, 15 /*P*/, 16 /*Q*/, 17 /*R*/, 18 /*S*/, - 19 /*T*/, 20 /*U*/, 21 /*V*/, 22 /*W*/, 23 /*X*/, 24 /*Y*/, 25 /*Z*/, - -1, -1, -1, -1, 63 /*_*/, -1, 26 /*a*/, - 27 /*b*/, 28 /*c*/, 29 /*d*/, 30 /*e*/, 31 /*f*/, 32 /*g*/, 33 /*h*/, - 34 /*i*/, 35 /*j*/, 36 /*k*/, 37 /*l*/, 38 /*m*/, 39 /*n*/, 40 /*o*/, - 41 /*p*/, 42 /*q*/, 43 /*r*/, 44 /*s*/, 45 /*t*/, 46 /*u*/, 47 /*v*/, - 48 /*w*/, 49 /*x*/, 50 /*y*/, 51 /*z*/, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1}; +static upb_Arena* arena_initslow(void* mem, size_t n, upb_alloc* alloc) { + const size_t first_block_overhead = sizeof(upb_Arena) + memblock_reserve; + upb_Arena* a; - /* Sign-extend return value so high bit will be set on any unexpected char. */ - return table[(unsigned)ch]; + /* We need to malloc the initial block. */ + n = first_block_overhead + 256; + if (!alloc || !(mem = upb_malloc(alloc, n))) { + return NULL; + } + + a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); + n -= sizeof(*a); + + a->head.alloc.func = &upb_Arena_doalloc; + a->block_alloc = alloc; + a->parent = a; + a->refcount = 1; + a->freelist = NULL; + a->freelist_tail = NULL; + a->cleanup_metadata = upb_cleanup_metadata(NULL, false); + + upb_Arena_addblock(a, a, mem, n); + + return a; } -static char* jsondec_partialbase64(jsondec* d, const char* ptr, const char* end, - char* out) { - int32_t val = -1; +upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) { + upb_Arena* a; - switch (end - ptr) { - case 2: - val = jsondec_base64_tablelookup(ptr[0]) << 18 | - jsondec_base64_tablelookup(ptr[1]) << 12; - out[0] = val >> 16; - out += 1; - break; - case 3: - val = jsondec_base64_tablelookup(ptr[0]) << 18 | - jsondec_base64_tablelookup(ptr[1]) << 12 | - jsondec_base64_tablelookup(ptr[2]) << 6; - out[0] = val >> 16; - out[1] = (val >> 8) & 0xff; - out += 2; - break; + if (n) { + /* Align initial pointer up so that we return properly-aligned pointers. */ + void* aligned = (void*)UPB_ALIGN_UP((uintptr_t)mem, UPB_MALLOC_ALIGN); + size_t delta = (uintptr_t)aligned - (uintptr_t)mem; + n = delta <= n ? n - delta : 0; + mem = aligned; } - if (val < 0) { - jsondec_err(d, "Corrupt base64"); + /* Round block size down to alignof(*a) since we will allocate the arena + * itself at the end. */ + n = UPB_ALIGN_DOWN(n, UPB_ALIGN_OF(upb_Arena)); + + if (UPB_UNLIKELY(n < sizeof(upb_Arena))) { + return arena_initslow(mem, n, alloc); } - return out; + a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); + + a->head.alloc.func = &upb_Arena_doalloc; + a->block_alloc = alloc; + a->parent = a; + a->refcount = 1; + a->last_size = UPB_MAX(128, n); + a->head.ptr = mem; + a->head.end = UPB_PTR_AT(mem, n - sizeof(*a), char); + a->freelist = NULL; + a->freelist_tail = NULL; + a->cleanup_metadata = upb_cleanup_metadata(NULL, true); + + return a; } -static size_t jsondec_base64(jsondec* d, upb_StringView str) { - /* We decode in place. This is safe because this is a new buffer (not - * aliasing the input) and because base64 decoding shrinks 4 bytes into 3. */ - char* out = (char*)str.data; - const char* ptr = str.data; - const char* end = ptr + str.size; - const char* end4 = ptr + (str.size & -4); /* Round down to multiple of 4. */ +static void arena_dofree(upb_Arena* a) { + mem_block* block = a->freelist; + UPB_ASSERT(a->parent == a); + UPB_ASSERT(a->refcount == 0); - for (; ptr < end4; ptr += 4, out += 3) { - int val = jsondec_base64_tablelookup(ptr[0]) << 18 | - jsondec_base64_tablelookup(ptr[1]) << 12 | - jsondec_base64_tablelookup(ptr[2]) << 6 | - jsondec_base64_tablelookup(ptr[3]) << 0; + while (block) { + /* Load first since we are deleting block. */ + mem_block* next = block->next; - if (val < 0) { - /* Junk chars or padding. Remove trailing padding, if any. */ - if (end - ptr == 4 && ptr[3] == '=') { - if (ptr[2] == '=') { - end -= 2; - } else { - end -= 1; - } + if (block->cleanups > 0) { + cleanup_ent* end = UPB_PTR_AT(block, block->size, void); + cleanup_ent* ptr = end - block->cleanups; + + for (; ptr < end; ptr++) { + ptr->cleanup(ptr->ud); } - break; } - out[0] = val >> 16; - out[1] = (val >> 8) & 0xff; - out[2] = val & 0xff; + upb_free(a->block_alloc, block); + block = next; } +} - if (ptr < end) { - /* Process remaining chars. We do not require padding. */ - out = jsondec_partialbase64(d, ptr, end, out); +void upb_Arena_Free(upb_Arena* a) { + a = arena_findroot(a); + if (--a->refcount == 0) arena_dofree(a); +} + +bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func) { + cleanup_ent* ent; + uint32_t* cleanups = upb_cleanup_pointer(a->cleanup_metadata); + + if (!cleanups || _upb_ArenaHas(a) < sizeof(cleanup_ent)) { + if (!upb_Arena_Allocblock(a, 128)) return false; /* Out of memory. */ + UPB_ASSERT(_upb_ArenaHas(a) >= sizeof(cleanup_ent)); + cleanups = upb_cleanup_pointer(a->cleanup_metadata); } - return out - str.data; + a->head.end -= sizeof(cleanup_ent); + ent = (cleanup_ent*)a->head.end; + (*cleanups)++; + UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent)); + + ent->cleanup = func; + ent->ud = ud; + + return true; } -/* Low-level integer parsing **************************************************/ +bool upb_Arena_Fuse(upb_Arena* a1, upb_Arena* a2) { + upb_Arena* r1 = arena_findroot(a1); + upb_Arena* r2 = arena_findroot(a2); -/* We use these hand-written routines instead of strto[u]l() because the "long - * long" variants aren't in c89. Also our version allows setting a ptr limit. */ + if (r1 == r2) return true; /* Already fused. */ -static const char* jsondec_buftouint64(jsondec* d, const char* ptr, - const char* end, uint64_t* val) { - uint64_t u64 = 0; - while (ptr < end) { - unsigned ch = *ptr - '0'; - if (ch >= 10) break; - if (u64 > UINT64_MAX / 10 || u64 * 10 > UINT64_MAX - ch) { - jsondec_err(d, "Integer overflow"); - } - u64 *= 10; - u64 += ch; - ptr++; + /* Do not fuse initial blocks since we cannot lifetime extend them. */ + if (upb_cleanup_has_initial_block(r1->cleanup_metadata)) return false; + if (upb_cleanup_has_initial_block(r2->cleanup_metadata)) return false; + + /* Only allow fuse with a common allocator */ + if (r1->block_alloc != r2->block_alloc) return false; + + /* We want to join the smaller tree to the larger tree. + * So swap first if they are backwards. */ + if (r1->refcount < r2->refcount) { + upb_Arena* tmp = r1; + r1 = r2; + r2 = tmp; } - *val = u64; - return ptr; + /* r1 takes over r2's freelist and refcount. */ + r1->refcount += r2->refcount; + if (r2->freelist_tail) { + UPB_ASSERT(r2->freelist_tail->next == NULL); + r2->freelist_tail->next = r1->freelist; + r1->freelist = r2->freelist; + } + r2->parent = r1; + return true; +} + + +#include + +// Must be last. + +static const char _upb_CTypeo_sizelg2[12] = { + 0, + 0, /* kUpb_CType_Bool */ + 2, /* kUpb_CType_Float */ + 2, /* kUpb_CType_Int32 */ + 2, /* kUpb_CType_UInt32 */ + 2, /* kUpb_CType_Enum */ + UPB_SIZE(2, 3), /* kUpb_CType_Message */ + 3, /* kUpb_CType_Double */ + 3, /* kUpb_CType_Int64 */ + 3, /* kUpb_CType_UInt64 */ + UPB_SIZE(3, 4), /* kUpb_CType_String */ + UPB_SIZE(3, 4), /* kUpb_CType_Bytes */ +}; + +upb_Array* upb_Array_New(upb_Arena* a, upb_CType type) { + return _upb_Array_New(a, 4, _upb_CTypeo_sizelg2[type]); +} + +size_t upb_Array_Size(const upb_Array* arr) { return arr->size; } + +upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i) { + upb_MessageValue ret; + const char* data = _upb_array_constptr(arr); + int lg2 = arr->data & 7; + UPB_ASSERT(i < arr->size); + memcpy(&ret, data + (i << lg2), 1 << lg2); + return ret; } -static const char* jsondec_buftoint64(jsondec* d, const char* ptr, - const char* end, int64_t* val) { - bool neg = false; - uint64_t u64; - - if (ptr != end && *ptr == '-') { - ptr++; - neg = true; - } +void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) { + char* data = _upb_array_ptr(arr); + int lg2 = arr->data & 7; + UPB_ASSERT(i < arr->size); + memcpy(data + (i << lg2), &val, 1 << lg2); +} - ptr = jsondec_buftouint64(d, ptr, end, &u64); - if (u64 > (uint64_t)INT64_MAX + neg) { - jsondec_err(d, "Integer overflow"); +bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) { + if (!upb_Array_Resize(arr, arr->size + 1, arena)) { + return false; } + upb_Array_Set(arr, arr->size - 1, val); + return true; +} - *val = neg ? -u64 : u64; - return ptr; +void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx, + size_t count) { + char* data = _upb_array_ptr(arr); + int lg2 = arr->data & 7; + memmove(&data[dst_idx << lg2], &data[src_idx << lg2], count << lg2); } -static uint64_t jsondec_strtouint64(jsondec* d, upb_StringView str) { - const char* end = str.data + str.size; - uint64_t ret; - if (jsondec_buftouint64(d, str.data, end, &ret) != end) { - jsondec_err(d, "Non-number characters in quoted integer"); +bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count, + upb_Arena* arena) { + UPB_ASSERT(i <= arr->size); + UPB_ASSERT(count + arr->size >= count); + size_t oldsize = arr->size; + if (!upb_Array_Resize(arr, arr->size + count, arena)) { + return false; } - return ret; + upb_Array_Move(arr, i + count, i, oldsize - i); + return true; } -static int64_t jsondec_strtoint64(jsondec* d, upb_StringView str) { - const char* end = str.data + str.size; - int64_t ret; - if (jsondec_buftoint64(d, str.data, end, &ret) != end) { - jsondec_err(d, "Non-number characters in quoted integer"); - } - return ret; +/* + * i end arr->size + * |------------|XXXXXXXX|--------| + */ +void upb_Array_Delete(upb_Array* arr, size_t i, size_t count) { + size_t end = i + count; + UPB_ASSERT(i <= end); + UPB_ASSERT(end <= arr->size); + upb_Array_Move(arr, i, end, arr->size - end); + arr->size -= count; } -/* Primitive value types ******************************************************/ +bool upb_Array_Resize(upb_Array* arr, size_t size, upb_Arena* arena) { + return _upb_Array_Resize(arr, size, arena); +} -/* Parse INT32 or INT64 value. */ -static upb_MessageValue jsondec_int(jsondec* d, const upb_FieldDef* f) { - upb_MessageValue val; - switch (jsondec_peek(d)) { - case JD_NUMBER: { - double dbl = jsondec_number(d); - if (dbl > 9223372036854774784.0 || dbl < -9223372036854775808.0) { - jsondec_err(d, "JSON number is out of range."); - } - val.int64_val = dbl; /* must be guarded, overflow here is UB */ - if (val.int64_val != dbl) { - jsondec_errf(d, "JSON number was not integral (%f != %" PRId64 ")", dbl, - val.int64_val); - } - break; - } - case JD_STRING: { - upb_StringView str = jsondec_string(d); - val.int64_val = jsondec_strtoint64(d, str); - break; - } - default: - jsondec_err(d, "Expected number or string"); - } +#include - if (upb_FieldDef_CType(f) == kUpb_CType_Int32 || - upb_FieldDef_CType(f) == kUpb_CType_Enum) { - if (val.int64_val > INT32_MAX || val.int64_val < INT32_MIN) { - jsondec_err(d, "Integer out of range."); - } - val.int32_val = (int32_t)val.int64_val; - } - return val; +// Must be last. + +// A few fake field types for our tables. +enum { + kUpb_FakeFieldType_FieldNotFound = 0, + kUpb_FakeFieldType_MessageSetItem = 19, +}; + +// DecodeOp: an action to be performed for a wire-type/field-type combination. +enum { + // Special ops: we don't write data to regular fields for these. + kUpb_DecodeOp_UnknownField = -1, + kUpb_DecodeOp_MessageSetItem = -2, + + // Scalar-only ops. + kUpb_DecodeOp_Scalar1Byte = 0, + kUpb_DecodeOp_Scalar4Byte = 2, + kUpb_DecodeOp_Scalar8Byte = 3, + kUpb_DecodeOp_Enum = 1, + + // Scalar/repeated ops. + kUpb_DecodeOp_String = 4, + kUpb_DecodeOp_Bytes = 5, + kUpb_DecodeOp_SubMessage = 6, + + // Repeated-only ops (also see macros below). + kUpb_DecodeOp_PackedEnum = 13, +}; + +// For packed fields it is helpful to be able to recover the lg2 of the data +// size from the op. +#define OP_FIXPCK_LG2(n) (n + 5) /* n in [2, 3] => op in [7, 8] */ +#define OP_VARPCK_LG2(n) (n + 9) /* n in [0, 2, 3] => op in [9, 11, 12] */ + +typedef union { + bool bool_val; + uint32_t uint32_val; + uint64_t uint64_val; + uint32_t size; +} wireval; + +static const char* _upb_Decoder_DecodeMessage(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable* layout); + +UPB_NORETURN static void* _upb_Decoder_ErrorJmp(upb_Decoder* d, + upb_DecodeStatus status) { + assert(status != kUpb_DecodeStatus_Ok); + UPB_LONGJMP(d->err, status); } -/* Parse UINT32 or UINT64 value. */ -static upb_MessageValue jsondec_uint(jsondec* d, const upb_FieldDef* f) { - upb_MessageValue val = {0}; +const char* _upb_FastDecoder_ErrorJmp(upb_Decoder* d, int status) { + assert(status != kUpb_DecodeStatus_Ok); + UPB_LONGJMP(d->err, status); + return NULL; +} +static void _upb_Decoder_VerifyUtf8(upb_Decoder* d, const char* buf, int len) { + if (!_upb_Decoder_VerifyUtf8Inline(buf, len)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_BadUtf8); + } +} - switch (jsondec_peek(d)) { - case JD_NUMBER: { - double dbl = jsondec_number(d); - if (dbl > 18446744073709549568.0 || dbl < 0) { - jsondec_err(d, "JSON number is out of range."); - } - val.uint64_val = dbl; /* must be guarded, overflow here is UB */ - if (val.uint64_val != dbl) { - jsondec_errf(d, "JSON number was not integral (%f != %" PRIu64 ")", dbl, - val.uint64_val); - } - break; - } - case JD_STRING: { - upb_StringView str = jsondec_string(d); - val.uint64_val = jsondec_strtouint64(d, str); - break; - } - default: - jsondec_err(d, "Expected number or string"); +static bool _upb_Decoder_Reserve(upb_Decoder* d, upb_Array* arr, size_t elem) { + bool need_realloc = arr->capacity - arr->size < elem; + if (need_realloc && !_upb_array_realloc(arr, arr->size + elem, &d->arena)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); } + return need_realloc; +} - if (upb_FieldDef_CType(f) == kUpb_CType_UInt32) { - if (val.uint64_val > UINT32_MAX) { - jsondec_err(d, "Integer out of range."); +typedef struct { + const char* ptr; + uint64_t val; +} _upb_DecodeLongVarintReturn; + +UPB_NOINLINE +static _upb_DecodeLongVarintReturn _upb_Decoder_DecodeLongVarint( + const char* ptr, uint64_t val) { + _upb_DecodeLongVarintReturn ret = {NULL, 0}; + uint64_t byte; + int i; + for (i = 1; i < 10; i++) { + byte = (uint8_t)ptr[i]; + val += (byte - 1) << (i * 7); + if (!(byte & 0x80)) { + ret.ptr = ptr + i + 1; + ret.val = val; + return ret; } - val.uint32_val = (uint32_t)val.uint64_val; } - - return val; + return ret; } -/* Parse DOUBLE or FLOAT value. */ -static upb_MessageValue jsondec_double(jsondec* d, const upb_FieldDef* f) { - upb_StringView str; - upb_MessageValue val = {0}; - - switch (jsondec_peek(d)) { - case JD_NUMBER: - val.double_val = jsondec_number(d); - break; - case JD_STRING: - str = jsondec_string(d); - if (jsondec_streql(str, "NaN")) { - val.double_val = NAN; - } else if (jsondec_streql(str, "Infinity")) { - val.double_val = INFINITY; - } else if (jsondec_streql(str, "-Infinity")) { - val.double_val = -INFINITY; - } else { - val.double_val = strtod(str.data, NULL); - } - break; - default: - jsondec_err(d, "Expected number or string"); +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeVarint(upb_Decoder* d, const char* ptr, + uint64_t* val) { + uint64_t byte = (uint8_t)*ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = byte; + return ptr + 1; + } else { + _upb_DecodeLongVarintReturn res = _upb_Decoder_DecodeLongVarint(ptr, byte); + if (!res.ptr) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + *val = res.val; + return res.ptr; } +} - if (upb_FieldDef_CType(f) == kUpb_CType_Float) { - if (val.double_val != INFINITY && val.double_val != -INFINITY && - (val.double_val > FLT_MAX || val.double_val < -FLT_MAX)) { - jsondec_err(d, "Float out of range"); +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeTag(upb_Decoder* d, const char* ptr, + uint32_t* val) { + uint64_t byte = (uint8_t)*ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = byte; + return ptr + 1; + } else { + const char* start = ptr; + _upb_DecodeLongVarintReturn res = _upb_Decoder_DecodeLongVarint(ptr, byte); + if (!res.ptr || res.ptr - start > 5 || res.val > UINT32_MAX) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); } - val.float_val = val.double_val; + *val = res.val; + return res.ptr; } +} - return val; +UPB_FORCEINLINE +static const char* upb_Decoder_DecodeSize(upb_Decoder* d, const char* ptr, + uint32_t* size) { + uint64_t size64; + ptr = _upb_Decoder_DecodeVarint(d, ptr, &size64); + if (size64 >= INT32_MAX || ptr - d->end + (int)size64 > d->limit) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + } + *size = size64; + return ptr; } -/* Parse STRING or BYTES value. */ -static upb_MessageValue jsondec_strfield(jsondec* d, const upb_FieldDef* f) { - upb_MessageValue val; - val.str_val = jsondec_string(d); - if (upb_FieldDef_CType(f) == kUpb_CType_Bytes) { - val.str_val.size = jsondec_base64(d, val.str_val); +static void _upb_Decoder_MungeInt32(wireval* val) { + if (!_upb_IsLittleEndian()) { + /* The next stage will memcpy(dst, &val, 4) */ + val->uint32_val = val->uint64_val; } - return val; } -static upb_MessageValue jsondec_enum(jsondec* d, const upb_FieldDef* f) { - switch (jsondec_peek(d)) { - case JD_STRING: { - upb_StringView str = jsondec_string(d); - const upb_EnumDef* e = upb_FieldDef_EnumSubDef(f); - const upb_EnumValueDef* ev = - upb_EnumDef_FindValueByNameWithSize(e, str.data, str.size); - upb_MessageValue val; - if (ev) { - val.int32_val = upb_EnumValueDef_Number(ev); - } else { - if (d->options & upb_JsonDecode_IgnoreUnknown) { - val.int32_val = 0; - } else { - jsondec_errf(d, "Unknown enumerator: '" UPB_STRINGVIEW_FORMAT "'", - UPB_STRINGVIEW_ARGS(str)); - } - } - return val; +static void _upb_Decoder_Munge(int type, wireval* val) { + switch (type) { + case kUpb_FieldType_Bool: + val->bool_val = val->uint64_val != 0; + break; + case kUpb_FieldType_SInt32: { + uint32_t n = val->uint64_val; + val->uint32_val = (n >> 1) ^ -(int32_t)(n & 1); + break; } - case JD_NULL: { - if (jsondec_isnullvalue(f)) { - upb_MessageValue val; - jsondec_null(d); - val.int32_val = 0; - return val; - } + case kUpb_FieldType_SInt64: { + uint64_t n = val->uint64_val; + val->uint64_val = (n >> 1) ^ -(int64_t)(n & 1); + break; } - /* Fallthrough. */ - default: - return jsondec_int(d, f); + case kUpb_FieldType_Int32: + case kUpb_FieldType_UInt32: + case kUpb_FieldType_Enum: + _upb_Decoder_MungeInt32(val); + break; } } -static upb_MessageValue jsondec_bool(jsondec* d, const upb_FieldDef* f) { - bool is_map_key = upb_FieldDef_Number(f) == 1 && - upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f)); - upb_MessageValue val; +static upb_Message* _upb_Decoder_NewSubMessage( + upb_Decoder* d, const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field) { + const upb_MiniTable* subl = subs[field->submsg_index].submsg; + upb_Message* msg = _upb_Message_New_inl(subl, &d->arena); + if (!msg) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + return msg; +} - if (is_map_key) { - upb_StringView str = jsondec_string(d); - if (jsondec_streql(str, "true")) { - val.bool_val = true; - } else if (jsondec_streql(str, "false")) { - val.bool_val = false; - } else { - jsondec_err(d, "Invalid boolean map key"); - } +UPB_NOINLINE +const char* _upb_Decoder_IsDoneFallback(upb_Decoder* d, const char* ptr, + int overrun) { + int status; + ptr = _upb_Decoder_IsDoneFallbackInline(d, ptr, overrun, &status); + if (ptr == NULL) _upb_Decoder_ErrorJmp(d, status); + return ptr; +} + +static const char* _upb_Decoder_ReadString(upb_Decoder* d, const char* ptr, + int size, upb_StringView* str) { + if (d->options & kUpb_DecodeOption_AliasString) { + str->data = ptr; } else { - switch (jsondec_peek(d)) { - case JD_TRUE: - val.bool_val = true; - jsondec_true(d); - break; - case JD_FALSE: - val.bool_val = false; - jsondec_false(d); - break; - default: - jsondec_err(d, "Expected true or false"); - } + char* data = upb_Arena_Malloc(&d->arena, size); + if (!data) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + memcpy(data, ptr, size); + str->data = data; } + str->size = size; + return ptr + size; +} - return val; +UPB_FORCEINLINE +static const char* _upb_Decoder_RecurseSubMessage(upb_Decoder* d, + const char* ptr, + upb_Message* submsg, + const upb_MiniTable* subl, + uint32_t expected_end_group) { + if (--d->depth < 0) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_MaxDepthExceeded); + } + ptr = _upb_Decoder_DecodeMessage(d, ptr, submsg, subl); + d->depth++; + if (d->end_group != expected_end_group) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + } + return ptr; } -/* Composite types (array/message/map) ****************************************/ +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeSubMessage( + upb_Decoder* d, const char* ptr, upb_Message* submsg, + const upb_MiniTable_Sub* subs, const upb_MiniTable_Field* field, int size) { + int saved_delta = _upb_Decoder_PushLimit(d, ptr, size); + const upb_MiniTable* subl = subs[field->submsg_index].submsg; + ptr = _upb_Decoder_RecurseSubMessage(d, ptr, submsg, subl, DECODE_NOGROUP); + _upb_Decoder_PopLimit(d, ptr, saved_delta); + return ptr; +} -static void jsondec_array(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { - upb_Array* arr = upb_Message_Mutable(msg, f, d->arena).array; +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeGroup(upb_Decoder* d, const char* ptr, + upb_Message* submsg, + const upb_MiniTable* subl, + uint32_t number) { + if (_upb_Decoder_IsDone(d, &ptr)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + } + ptr = _upb_Decoder_RecurseSubMessage(d, ptr, submsg, subl, number); + d->end_group = DECODE_NOGROUP; + return ptr; +} - jsondec_arrstart(d); - while (jsondec_arrnext(d)) { - upb_MessageValue elem = jsondec_value(d, f); - upb_Array_Append(arr, elem, d->arena); - } - jsondec_arrend(d); +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeUnknownGroup(upb_Decoder* d, + const char* ptr, + uint32_t number) { + return _upb_Decoder_DecodeGroup(d, ptr, NULL, NULL, number); } -static void jsondec_map(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { - upb_Map* map = upb_Message_Mutable(msg, f, d->arena).map; - const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); - const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); - const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeKnownGroup( + upb_Decoder* d, const char* ptr, upb_Message* submsg, + const upb_MiniTable_Sub* subs, const upb_MiniTable_Field* field) { + const upb_MiniTable* subl = subs[field->submsg_index].submsg; + return _upb_Decoder_DecodeGroup(d, ptr, submsg, subl, field->number); +} - jsondec_objstart(d); - while (jsondec_objnext(d)) { - upb_MessageValue key, val; - key = jsondec_value(d, key_f); - jsondec_entrysep(d); - val = jsondec_value(d, val_f); - upb_Map_Set(map, key, val, d->arena); - } - jsondec_objend(d); +static char* upb_Decoder_EncodeVarint32(uint32_t val, char* ptr) { + do { + uint8_t byte = val & 0x7fU; + val >>= 7; + if (val) byte |= 0x80U; + *(ptr++) = byte; + } while (val); + return ptr; } -static void jsondec_tomsg(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { - jsondec_object(d, msg, m); - } else { - jsondec_wellknown(d, msg, m); +static void _upb_Decoder_AddUnknownVarints(upb_Decoder* d, upb_Message* msg, + uint32_t val1, uint32_t val2) { + char buf[20]; + char* end = buf; + end = upb_Decoder_EncodeVarint32(val1, end); + end = upb_Decoder_EncodeVarint32(val2, end); + + if (!_upb_Message_AddUnknown(msg, buf, end - buf, &d->arena)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); } } -static upb_MessageValue jsondec_msg(jsondec* d, const upb_FieldDef* f) { - const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); - upb_Message* msg = upb_Message_New(m, d->arena); - upb_MessageValue val; +UPB_NOINLINE +static bool _upb_Decoder_CheckEnumSlow(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable_Enum* e, + const upb_MiniTable_Field* field, + uint32_t v) { + if (_upb_MiniTable_CheckEnumValueSlow(e, v)) return true; - jsondec_tomsg(d, msg, m); - val.msg_val = msg; - return val; + // Unrecognized enum goes into unknown fields. + // For packed fields the tag could be arbitrarily far in the past, so we + // just re-encode the tag and value here. + uint32_t tag = ((uint32_t)field->number << 3) | kUpb_WireType_Varint; + upb_Message* unknown_msg = + field->mode & kUpb_LabelFlags_IsExtension ? d->unknown_msg : msg; + _upb_Decoder_AddUnknownVarints(d, unknown_msg, tag, v); + return false; } -static void jsondec_field(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - upb_StringView name; - const upb_FieldDef* f; - const upb_FieldDef* preserved; +UPB_FORCEINLINE +static bool _upb_Decoder_CheckEnum(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable_Enum* e, + const upb_MiniTable_Field* field, + wireval* val) { + uint32_t v = val->uint32_val; - name = jsondec_string(d); - jsondec_entrysep(d); + _kUpb_FastEnumCheck_Status status = _upb_MiniTable_CheckEnumValueFast(e, v); + if (UPB_LIKELY(status == _kUpb_FastEnumCheck_ValueIsInEnum)) return true; + return _upb_Decoder_CheckEnumSlow(d, ptr, msg, e, field, v); +} - if (name.size >= 2 && name.data[0] == '[' && - name.data[name.size - 1] == ']') { - f = upb_DefPool_FindExtensionByNameWithSize(d->symtab, name.data + 1, - name.size - 2); - if (f && upb_FieldDef_ContainingType(f) != m) { - jsondec_errf( - d, "Extension %s extends message %s, but was seen in message %s", - upb_FieldDef_FullName(f), - upb_MessageDef_FullName(upb_FieldDef_ContainingType(f)), - upb_MessageDef_FullName(m)); - } - } else { - f = upb_MessageDef_FindByJsonNameWithSize(m, name.data, name.size); - } +UPB_NOINLINE +static const char* _upb_Decoder_DecodeEnumArray( + upb_Decoder* d, const char* ptr, upb_Message* msg, upb_Array* arr, + const upb_MiniTable_Sub* subs, const upb_MiniTable_Field* field, + wireval* val) { + const upb_MiniTable_Enum* e = subs[field->submsg_index].subenum; + if (!_upb_Decoder_CheckEnum(d, ptr, msg, e, field, val)) return ptr; + void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->size * 4, void); + arr->size++; + memcpy(mem, val, 4); + return ptr; +} - if (!f) { - if ((d->options & upb_JsonDecode_IgnoreUnknown) == 0) { - jsondec_errf(d, "No such field: " UPB_STRINGVIEW_FORMAT, - UPB_STRINGVIEW_ARGS(name)); +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeFixedPacked( + upb_Decoder* d, const char* ptr, upb_Array* arr, wireval* val, + const upb_MiniTable_Field* field, int lg2) { + int mask = (1 << lg2) - 1; + size_t count = val->size >> lg2; + if ((val->size & mask) != 0) { + // Length isn't a round multiple of elem size. + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + } + _upb_Decoder_Reserve(d, arr, count); + void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << lg2, void); + arr->size += count; + // Note: if/when the decoder supports multi-buffer input, we will need to + // handle buffer seams here. + if (_upb_IsLittleEndian()) { + memcpy(mem, ptr, val->size); + ptr += val->size; + } else { + const char* end = ptr + val->size; + char* dst = mem; + while (ptr < end) { + if (lg2 == 2) { + uint32_t val; + memcpy(&val, ptr, sizeof(val)); + val = _upb_BigEndian_Swap32(val); + memcpy(dst, &val, sizeof(val)); + } else { + UPB_ASSERT(lg2 == 3); + uint64_t val; + memcpy(&val, ptr, sizeof(val)); + val = _upb_BigEndian_Swap64(val); + memcpy(dst, &val, sizeof(val)); + } + ptr += 1 << lg2; + dst += 1 << lg2; } - jsondec_skipval(d); - return; } - if (jsondec_peek(d) == JD_NULL && !jsondec_isvalue(f)) { - /* JSON "null" indicates a default value, so no need to set anything. */ - jsondec_null(d); - return; - } + return ptr; +} - if (upb_FieldDef_RealContainingOneof(f) && - upb_Message_WhichOneof(msg, upb_FieldDef_ContainingOneof(f))) { - jsondec_err(d, "More than one field for this oneof."); +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeVarintPacked( + upb_Decoder* d, const char* ptr, upb_Array* arr, wireval* val, + const upb_MiniTable_Field* field, int lg2) { + int scale = 1 << lg2; + int saved_limit = _upb_Decoder_PushLimit(d, ptr, val->size); + char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << lg2, void); + while (!_upb_Decoder_IsDone(d, &ptr)) { + wireval elem; + ptr = _upb_Decoder_DecodeVarint(d, ptr, &elem.uint64_val); + _upb_Decoder_Munge(field->descriptortype, &elem); + if (_upb_Decoder_Reserve(d, arr, 1)) { + out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << lg2, void); + } + arr->size++; + memcpy(out, &elem, scale); + out += scale; } + _upb_Decoder_PopLimit(d, ptr, saved_limit); + return ptr; +} - preserved = d->debug_field; - d->debug_field = f; - - if (upb_FieldDef_IsMap(f)) { - jsondec_map(d, msg, f); - } else if (upb_FieldDef_IsRepeated(f)) { - jsondec_array(d, msg, f); - } else if (upb_FieldDef_IsSubMessage(f)) { - upb_Message* submsg = upb_Message_Mutable(msg, f, d->arena).msg; - const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); - jsondec_tomsg(d, submsg, subm); - } else { - upb_MessageValue val = jsondec_value(d, f); - upb_Message_Set(msg, f, val, d->arena); +UPB_NOINLINE +static const char* _upb_Decoder_DecodeEnumPacked( + upb_Decoder* d, const char* ptr, upb_Message* msg, upb_Array* arr, + const upb_MiniTable_Sub* subs, const upb_MiniTable_Field* field, + wireval* val) { + const upb_MiniTable_Enum* e = subs[field->submsg_index].subenum; + int saved_limit = _upb_Decoder_PushLimit(d, ptr, val->size); + char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size * 4, void); + while (!_upb_Decoder_IsDone(d, &ptr)) { + wireval elem; + ptr = _upb_Decoder_DecodeVarint(d, ptr, &elem.uint64_val); + _upb_Decoder_MungeInt32(&elem); + if (!_upb_Decoder_CheckEnum(d, ptr, msg, e, field, &elem)) { + continue; + } + if (_upb_Decoder_Reserve(d, arr, 1)) { + out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size * 4, void); + } + arr->size++; + memcpy(out, &elem, 4); + out += 4; } - - d->debug_field = preserved; + _upb_Decoder_PopLimit(d, ptr, saved_limit); + return ptr; } -static void jsondec_object(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - jsondec_objstart(d); - while (jsondec_objnext(d)) { - jsondec_field(d, msg, m); - } - jsondec_objend(d); +upb_Array* _upb_Decoder_CreateArray(upb_Decoder* d, + const upb_MiniTable_Field* field) { + /* Maps descriptor type -> elem_size_lg2. */ + static const uint8_t kElemSizeLg2[] = { + [0] = -1, // invalid descriptor type + [kUpb_FieldType_Double] = 3, + [kUpb_FieldType_Float] = 2, + [kUpb_FieldType_Int64] = 3, + [kUpb_FieldType_UInt64] = 3, + [kUpb_FieldType_Int32] = 2, + [kUpb_FieldType_Fixed64] = 3, + [kUpb_FieldType_Fixed32] = 2, + [kUpb_FieldType_Bool] = 0, + [kUpb_FieldType_String] = UPB_SIZE(3, 4), + [kUpb_FieldType_Group] = UPB_SIZE(2, 3), + [kUpb_FieldType_Message] = UPB_SIZE(2, 3), + [kUpb_FieldType_Bytes] = UPB_SIZE(3, 4), + [kUpb_FieldType_UInt32] = 2, + [kUpb_FieldType_Enum] = 2, + [kUpb_FieldType_SFixed32] = 2, + [kUpb_FieldType_SFixed64] = 3, + [kUpb_FieldType_SInt32] = 2, + [kUpb_FieldType_SInt64] = 3, + }; + + size_t lg2 = kElemSizeLg2[field->descriptortype]; + upb_Array* ret = _upb_Array_New(&d->arena, 4, lg2); + if (!ret) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + return ret; } -static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f) { - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Bool: - return jsondec_bool(d, f); - case kUpb_CType_Float: - case kUpb_CType_Double: - return jsondec_double(d, f); - case kUpb_CType_UInt32: - case kUpb_CType_UInt64: - return jsondec_uint(d, f); - case kUpb_CType_Int32: - case kUpb_CType_Int64: - return jsondec_int(d, f); - case kUpb_CType_String: - case kUpb_CType_Bytes: - return jsondec_strfield(d, f); - case kUpb_CType_Enum: - return jsondec_enum(d, f); - case kUpb_CType_Message: - return jsondec_msg(d, f); +static const char* _upb_Decoder_DecodeToArray(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field, + wireval* val, int op) { + upb_Array** arrp = UPB_PTR_AT(msg, field->offset, void); + upb_Array* arr = *arrp; + void* mem; + + if (arr) { + _upb_Decoder_Reserve(d, arr, 1); + } else { + arr = _upb_Decoder_CreateArray(d, field); + *arrp = arr; + } + + switch (op) { + case kUpb_DecodeOp_Scalar1Byte: + case kUpb_DecodeOp_Scalar4Byte: + case kUpb_DecodeOp_Scalar8Byte: + /* Append scalar value. */ + mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << op, void); + arr->size++; + memcpy(mem, val, 1 << op); + return ptr; + case kUpb_DecodeOp_String: + _upb_Decoder_VerifyUtf8(d, ptr, val->size); + /* Fallthrough. */ + case kUpb_DecodeOp_Bytes: { + /* Append bytes. */ + upb_StringView* str = (upb_StringView*)_upb_array_ptr(arr) + arr->size; + arr->size++; + return _upb_Decoder_ReadString(d, ptr, val->size, str); + } + case kUpb_DecodeOp_SubMessage: { + /* Append submessage / group. */ + upb_Message* submsg = _upb_Decoder_NewSubMessage(d, subs, field); + *UPB_PTR_AT(_upb_array_ptr(arr), arr->size * sizeof(void*), + upb_Message*) = submsg; + arr->size++; + if (UPB_UNLIKELY(field->descriptortype == kUpb_FieldType_Group)) { + return _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, subs, field); + } else { + return _upb_Decoder_DecodeSubMessage(d, ptr, submsg, subs, field, + val->size); + } + } + case OP_FIXPCK_LG2(2): + case OP_FIXPCK_LG2(3): + return _upb_Decoder_DecodeFixedPacked(d, ptr, arr, val, field, + op - OP_FIXPCK_LG2(0)); + case OP_VARPCK_LG2(0): + case OP_VARPCK_LG2(2): + case OP_VARPCK_LG2(3): + return _upb_Decoder_DecodeVarintPacked(d, ptr, arr, val, field, + op - OP_VARPCK_LG2(0)); + case kUpb_DecodeOp_Enum: + return _upb_Decoder_DecodeEnumArray(d, ptr, msg, arr, subs, field, val); + case kUpb_DecodeOp_PackedEnum: + return _upb_Decoder_DecodeEnumPacked(d, ptr, msg, arr, subs, field, val); default: UPB_UNREACHABLE(); } } -/* Well-known types ***********************************************************/ +upb_Map* _upb_Decoder_CreateMap(upb_Decoder* d, const upb_MiniTable* entry) { + /* Maps descriptor type -> upb map size. */ + static const uint8_t kSizeInMap[] = { + [0] = -1, // invalid descriptor type */ + [kUpb_FieldType_Double] = 8, + [kUpb_FieldType_Float] = 4, + [kUpb_FieldType_Int64] = 8, + [kUpb_FieldType_UInt64] = 8, + [kUpb_FieldType_Int32] = 4, + [kUpb_FieldType_Fixed64] = 8, + [kUpb_FieldType_Fixed32] = 4, + [kUpb_FieldType_Bool] = 1, + [kUpb_FieldType_String] = UPB_MAPTYPE_STRING, + [kUpb_FieldType_Group] = sizeof(void*), + [kUpb_FieldType_Message] = sizeof(void*), + [kUpb_FieldType_Bytes] = UPB_MAPTYPE_STRING, + [kUpb_FieldType_UInt32] = 4, + [kUpb_FieldType_Enum] = 4, + [kUpb_FieldType_SFixed32] = 4, + [kUpb_FieldType_SFixed64] = 8, + [kUpb_FieldType_SInt32] = 4, + [kUpb_FieldType_SInt64] = 8, + }; -static int jsondec_tsdigits(jsondec* d, const char** ptr, size_t digits, - const char* after) { - uint64_t val; - const char* p = *ptr; - const char* end = p + digits; - size_t after_len = after ? strlen(after) : 0; + const upb_MiniTable_Field* key_field = &entry->fields[0]; + const upb_MiniTable_Field* val_field = &entry->fields[1]; + char key_size = kSizeInMap[key_field->descriptortype]; + char val_size = kSizeInMap[val_field->descriptortype]; + UPB_ASSERT(key_field->offset == 0); + UPB_ASSERT(val_field->offset == sizeof(upb_StringView)); + upb_Map* ret = _upb_Map_New(&d->arena, key_size, val_size); + if (!ret) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + return ret; +} - UPB_ASSERT(digits <= 9); /* int can't overflow. */ +static const char* _upb_Decoder_DecodeToMap(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field, + wireval* val) { + upb_Map** map_p = UPB_PTR_AT(msg, field->offset, upb_Map*); + upb_Map* map = *map_p; + upb_MapEntry ent; + const upb_MiniTable* entry = subs[field->submsg_index].submsg; - if (jsondec_buftouint64(d, p, end, &val) != end || - (after_len && memcmp(end, after, after_len) != 0)) { - jsondec_err(d, "Malformed timestamp"); + if (!map) { + map = _upb_Decoder_CreateMap(d, entry); + *map_p = map; } - UPB_ASSERT(val < INT_MAX); + /* Parse map entry. */ + memset(&ent, 0, sizeof(ent)); - *ptr = end + after_len; - return (int)val; + if (entry->fields[1].descriptortype == kUpb_FieldType_Message || + entry->fields[1].descriptortype == kUpb_FieldType_Group) { + /* Create proactively to handle the case where it doesn't appear. */ + ent.v.val = + upb_value_ptr(_upb_Message_New(entry->subs[0].submsg, &d->arena)); + } + + const char* start = ptr; + ptr = _upb_Decoder_DecodeSubMessage(d, ptr, &ent.k, subs, field, val->size); + // check if ent had any unknown fields + size_t size; + upb_Message_GetUnknown(&ent.k, &size); + if (size != 0) { + uint32_t tag = ((uint32_t)field->number << 3) | kUpb_WireType_Delimited; + _upb_Decoder_AddUnknownVarints(d, msg, tag, (uint32_t)(ptr - start)); + if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + } else { + if (_upb_Map_Insert(map, &ent.k, map->key_size, &ent.v, map->val_size, + &d->arena) == _kUpb_MapInsertStatus_OutOfMemory) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + } + return ptr; } -static int jsondec_nanos(jsondec* d, const char** ptr, const char* end) { - uint64_t nanos = 0; - const char* p = *ptr; +static const char* _upb_Decoder_DecodeToSubMessage( + upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTable_Sub* subs, const upb_MiniTable_Field* field, + wireval* val, int op) { + void* mem = UPB_PTR_AT(msg, field->offset, void); + int type = field->descriptortype; - if (p != end && *p == '.') { - const char* nano_end = jsondec_buftouint64(d, p + 1, end, &nanos); - int digits = (int)(nano_end - p - 1); - int exp_lg10 = 9 - digits; - if (digits > 9) { - jsondec_err(d, "Too many digits for partial seconds"); + if (UPB_UNLIKELY(op == kUpb_DecodeOp_Enum) && + !_upb_Decoder_CheckEnum(d, ptr, msg, subs[field->submsg_index].subenum, + field, val)) { + return ptr; + } + + /* Set presence if necessary. */ + if (field->presence > 0) { + _upb_sethas_field(msg, field); + } else if (field->presence < 0) { + /* Oneof case */ + uint32_t* oneof_case = _upb_oneofcase_field(msg, field); + if (op == kUpb_DecodeOp_SubMessage && *oneof_case != field->number) { + memset(mem, 0, sizeof(void*)); } - while (exp_lg10--) nanos *= 10; - *ptr = nano_end; + *oneof_case = field->number; } - UPB_ASSERT(nanos < INT_MAX); + /* Store into message. */ + switch (op) { + case kUpb_DecodeOp_SubMessage: { + upb_Message** submsgp = mem; + upb_Message* submsg = *submsgp; + if (!submsg) { + submsg = _upb_Decoder_NewSubMessage(d, subs, field); + *submsgp = submsg; + } + if (UPB_UNLIKELY(type == kUpb_FieldType_Group)) { + ptr = _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, subs, field); + } else { + ptr = _upb_Decoder_DecodeSubMessage(d, ptr, submsg, subs, field, + val->size); + } + break; + } + case kUpb_DecodeOp_String: + _upb_Decoder_VerifyUtf8(d, ptr, val->size); + /* Fallthrough. */ + case kUpb_DecodeOp_Bytes: + return _upb_Decoder_ReadString(d, ptr, val->size, mem); + case kUpb_DecodeOp_Scalar8Byte: + memcpy(mem, val, 8); + break; + case kUpb_DecodeOp_Enum: + case kUpb_DecodeOp_Scalar4Byte: + memcpy(mem, val, 4); + break; + case kUpb_DecodeOp_Scalar1Byte: + memcpy(mem, val, 1); + break; + default: + UPB_UNREACHABLE(); + } - return (int)nanos; + return ptr; } -/* jsondec_epochdays(1970, 1, 1) == 1970-01-01 == 0. */ -int jsondec_epochdays(int y, int m, int d) { - const uint32_t year_base = 4800; /* Before min year, multiple of 400. */ - const uint32_t m_adj = m - 3; /* March-based month. */ - const uint32_t carry = m_adj > (uint32_t)m ? 1 : 0; - const uint32_t adjust = carry ? 12 : 0; - const uint32_t y_adj = y + year_base - carry; - const uint32_t month_days = ((m_adj + adjust) * 62719 + 769) / 2048; - const uint32_t leap_days = y_adj / 4 - y_adj / 100 + y_adj / 400; - return y_adj * 365 + leap_days + month_days + (d - 1) - 2472632; +UPB_NOINLINE +const char* _upb_Decoder_CheckRequired(upb_Decoder* d, const char* ptr, + const upb_Message* msg, + const upb_MiniTable* l) { + assert(l->required_count); + if (UPB_LIKELY((d->options & kUpb_DecodeOption_CheckRequired) == 0)) { + return ptr; + } + uint64_t msg_head; + memcpy(&msg_head, msg, 8); + msg_head = _upb_BigEndian_Swap64(msg_head); + if (upb_MiniTable_requiredmask(l) & ~msg_head) { + d->missing_required = true; + } + return ptr; } -static int64_t jsondec_unixtime(int y, int m, int d, int h, int min, int s) { - return (int64_t)jsondec_epochdays(y, m, d) * 86400 + h * 3600 + min * 60 + s; +UPB_FORCEINLINE +static bool _upb_Decoder_TryFastDispatch(upb_Decoder* d, const char** ptr, + upb_Message* msg, + const upb_MiniTable* layout) { +#if UPB_FASTTABLE + if (layout && layout->table_mask != (unsigned char)-1) { + uint16_t tag = _upb_FastDecoder_LoadTag(*ptr); + intptr_t table = decode_totable(layout); + *ptr = _upb_FastDecoder_TagDispatch(d, *ptr, msg, table, 0, tag); + return true; + } +#endif + return false; } -static void jsondec_timestamp(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - upb_MessageValue seconds; - upb_MessageValue nanos; - upb_StringView str = jsondec_string(d); - const char* ptr = str.data; - const char* end = ptr + str.size; - - if (str.size < 20) goto malformed; - - { - /* 1972-01-01T01:00:00 */ - int year = jsondec_tsdigits(d, &ptr, 4, "-"); - int mon = jsondec_tsdigits(d, &ptr, 2, "-"); - int day = jsondec_tsdigits(d, &ptr, 2, "T"); - int hour = jsondec_tsdigits(d, &ptr, 2, ":"); - int min = jsondec_tsdigits(d, &ptr, 2, ":"); - int sec = jsondec_tsdigits(d, &ptr, 2, NULL); - - seconds.int64_val = jsondec_unixtime(year, mon, day, hour, min, sec); +static const char* upb_Decoder_SkipField(upb_Decoder* d, const char* ptr, + uint32_t tag) { + int field_number = tag >> 3; + int wire_type = tag & 7; + switch (wire_type) { + case kUpb_WireType_Varint: { + uint64_t val; + return _upb_Decoder_DecodeVarint(d, ptr, &val); + } + case kUpb_WireType_64Bit: + return ptr + 8; + case kUpb_WireType_32Bit: + return ptr + 4; + case kUpb_WireType_Delimited: { + uint32_t size; + ptr = upb_Decoder_DecodeSize(d, ptr, &size); + return ptr + size; + } + case kUpb_WireType_StartGroup: + return _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); + default: + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); } +} - nanos.int32_val = jsondec_nanos(d, &ptr, end); - - { - /* [+-]08:00 or Z */ - int ofs_hour = 0; - int ofs_min = 0; - bool neg = false; +enum { + kStartItemTag = ((1 << 3) | kUpb_WireType_StartGroup), + kEndItemTag = ((1 << 3) | kUpb_WireType_EndGroup), + kTypeIdTag = ((2 << 3) | kUpb_WireType_Varint), + kMessageTag = ((3 << 3) | kUpb_WireType_Delimited), +}; - if (ptr == end) goto malformed; +static void upb_Decoder_AddKnownMessageSetItem( + upb_Decoder* d, upb_Message* msg, const upb_MiniTable_Extension* item_mt, + const char* data, uint32_t size) { + upb_Message_Extension* ext = + _upb_Message_GetOrCreateExtension(msg, item_mt, &d->arena); + if (UPB_UNLIKELY(!ext)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + upb_Message* submsg = + _upb_Decoder_NewSubMessage(d, &ext->ext->sub, &ext->ext->field); + upb_DecodeStatus status = upb_Decode(data, size, submsg, item_mt->sub.submsg, + d->extreg, d->options, &d->arena); + memcpy(&ext->data, &submsg, sizeof(submsg)); + if (status != kUpb_DecodeStatus_Ok) _upb_Decoder_ErrorJmp(d, status); +} + +static void upb_Decoder_AddUnknownMessageSetItem(upb_Decoder* d, + upb_Message* msg, + uint32_t type_id, + const char* message_data, + uint32_t message_size) { + char buf[60]; + char* ptr = buf; + ptr = upb_Decoder_EncodeVarint32(kStartItemTag, ptr); + ptr = upb_Decoder_EncodeVarint32(kTypeIdTag, ptr); + ptr = upb_Decoder_EncodeVarint32(type_id, ptr); + ptr = upb_Decoder_EncodeVarint32(kMessageTag, ptr); + ptr = upb_Decoder_EncodeVarint32(message_size, ptr); + char* split = ptr; + + ptr = upb_Decoder_EncodeVarint32(kEndItemTag, ptr); + char* end = ptr; + + if (!_upb_Message_AddUnknown(msg, buf, split - buf, &d->arena) || + !_upb_Message_AddUnknown(msg, message_data, message_size, &d->arena) || + !_upb_Message_AddUnknown(msg, split, end - split, &d->arena)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } +} + +static void upb_Decoder_AddMessageSetItem(upb_Decoder* d, upb_Message* msg, + const upb_MiniTable* layout, + uint32_t type_id, const char* data, + uint32_t size) { + const upb_MiniTable_Extension* item_mt = + _upb_extreg_get(d->extreg, layout, type_id); + if (item_mt) { + upb_Decoder_AddKnownMessageSetItem(d, msg, item_mt, data, size); + } else { + upb_Decoder_AddUnknownMessageSetItem(d, msg, type_id, data, size); + } +} - switch (*ptr++) { - case '-': - neg = true; - /* fallthrough */ - case '+': - if ((end - ptr) != 5) goto malformed; - ofs_hour = jsondec_tsdigits(d, &ptr, 2, ":"); - ofs_min = jsondec_tsdigits(d, &ptr, 2, NULL); - ofs_min = ((ofs_hour * 60) + ofs_min) * 60; - seconds.int64_val += (neg ? ofs_min : -ofs_min); +static const char* upb_Decoder_DecodeMessageSetItem( + upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTable* layout) { + uint32_t type_id = 0; + upb_StringView preserved = {NULL, 0}; + typedef enum { + kUpb_HaveId = 1 << 0, + kUpb_HavePayload = 1 << 1, + } StateMask; + StateMask state_mask = 0; + while (!_upb_Decoder_IsDone(d, &ptr)) { + uint32_t tag; + ptr = _upb_Decoder_DecodeTag(d, ptr, &tag); + switch (tag) { + case kEndItemTag: + return ptr; + case kTypeIdTag: { + uint64_t tmp; + ptr = _upb_Decoder_DecodeVarint(d, ptr, &tmp); + if (state_mask & kUpb_HaveId) break; // Ignore dup. + state_mask |= kUpb_HaveId; + type_id = tmp; + if (state_mask & kUpb_HavePayload) { + upb_Decoder_AddMessageSetItem(d, msg, layout, type_id, preserved.data, + preserved.size); + } break; - case 'Z': - if (ptr != end) goto malformed; + } + case kMessageTag: { + uint32_t size; + ptr = upb_Decoder_DecodeSize(d, ptr, &size); + const char* data = ptr; + ptr += size; + if (state_mask & kUpb_HavePayload) break; // Ignore dup. + state_mask |= kUpb_HavePayload; + if (state_mask & kUpb_HaveId) { + upb_Decoder_AddMessageSetItem(d, msg, layout, type_id, data, size); + } else { + // Out of order, we must preserve the payload. + preserved.data = data; + preserved.size = size; + } break; + } default: - goto malformed; + // We do not preserve unexpected fields inside a message set item. + ptr = upb_Decoder_SkipField(d, ptr, tag); + break; } } + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); +} - if (seconds.int64_val < -62135596800) { - jsondec_err(d, "Timestamp out of range"); +static const upb_MiniTable_Field* _upb_Decoder_FindField( + upb_Decoder* d, const upb_MiniTable* l, uint32_t field_number, + int* last_field_index) { + static upb_MiniTable_Field none = { + 0, 0, 0, 0, kUpb_FakeFieldType_FieldNotFound, 0}; + if (l == NULL) return &none; + + size_t idx = ((size_t)field_number) - 1; // 0 wraps to SIZE_MAX + if (idx < l->dense_below) { + /* Fastest case: index into dense fields. */ + goto found; } - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, - d->arena); - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); - return; + if (l->dense_below < l->field_count) { + /* Linear search non-dense fields. Resume scanning from last_field_index + * since fields are usually in order. */ + int last = *last_field_index; + for (idx = last; idx < l->field_count; idx++) { + if (l->fields[idx].number == field_number) { + goto found; + } + } + + for (idx = l->dense_below; idx < last; idx++) { + if (l->fields[idx].number == field_number) { + goto found; + } + } + } + + if (d->extreg) { + switch (l->ext) { + case kUpb_ExtMode_Extendable: { + const upb_MiniTable_Extension* ext = + _upb_extreg_get(d->extreg, l, field_number); + if (ext) return &ext->field; + break; + } + case kUpb_ExtMode_IsMessageSet: + if (field_number == _UPB_MSGSET_ITEM) { + static upb_MiniTable_Field item = { + 0, 0, 0, 0, kUpb_FakeFieldType_MessageSetItem, 0}; + return &item; + } + break; + } + } -malformed: - jsondec_err(d, "Malformed timestamp"); -} + return &none; /* Unknown field. */ -static void jsondec_duration(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - upb_MessageValue seconds; - upb_MessageValue nanos; - upb_StringView str = jsondec_string(d); - const char* ptr = str.data; - const char* end = ptr + str.size; - const int64_t max = (uint64_t)3652500 * 86400; +found: + UPB_ASSERT(l->fields[idx].number == field_number); + *last_field_index = idx; + return &l->fields[idx]; +} - /* "3.000000001s", "3s", etc. */ - ptr = jsondec_buftoint64(d, ptr, end, &seconds.int64_val); - nanos.int32_val = jsondec_nanos(d, &ptr, end); +int _upb_Decoder_GetVarintOp(const upb_MiniTable_Field* field) { + static const int8_t kVarintOps[] = { + [kUpb_FakeFieldType_FieldNotFound] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Double] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Float] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Int64] = kUpb_DecodeOp_Scalar8Byte, + [kUpb_FieldType_UInt64] = kUpb_DecodeOp_Scalar8Byte, + [kUpb_FieldType_Int32] = kUpb_DecodeOp_Scalar4Byte, + [kUpb_FieldType_Fixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Fixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Bool] = kUpb_DecodeOp_Scalar1Byte, + [kUpb_FieldType_String] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Message] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Bytes] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_UInt32] = kUpb_DecodeOp_Scalar4Byte, + [kUpb_FieldType_Enum] = kUpb_DecodeOp_Enum, + [kUpb_FieldType_SFixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SFixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SInt32] = kUpb_DecodeOp_Scalar4Byte, + [kUpb_FieldType_SInt64] = kUpb_DecodeOp_Scalar8Byte, + [kUpb_FakeFieldType_MessageSetItem] = kUpb_DecodeOp_UnknownField, + }; - if (end - ptr != 1 || *ptr != 's') { - jsondec_err(d, "Malformed duration"); - } + return kVarintOps[field->descriptortype]; +} + +int _upb_Decoder_GetDelimitedOp(const upb_MiniTable* mt, + const upb_MiniTable_Field* field) { + enum { kRepeatedBase = 19 }; + + static const int8_t kDelimitedOps[] = { + /* For non-repeated field type. */ + [kUpb_FakeFieldType_FieldNotFound] = + kUpb_DecodeOp_UnknownField, // Field not found. + [kUpb_FieldType_Double] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Float] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Int64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_UInt64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Int32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Fixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Fixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Bool] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_String] = kUpb_DecodeOp_String, + [kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Message] = kUpb_DecodeOp_SubMessage, + [kUpb_FieldType_Bytes] = kUpb_DecodeOp_Bytes, + [kUpb_FieldType_UInt32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Enum] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SFixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SFixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SInt32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SInt64] = kUpb_DecodeOp_UnknownField, + [kUpb_FakeFieldType_MessageSetItem] = kUpb_DecodeOp_UnknownField, + // For repeated field type. */ + [kRepeatedBase + kUpb_FieldType_Double] = OP_FIXPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_Float] = OP_FIXPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Int64] = OP_VARPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_UInt64] = OP_VARPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_Int32] = OP_VARPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Fixed64] = OP_FIXPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_Fixed32] = OP_FIXPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Bool] = OP_VARPCK_LG2(0), + [kRepeatedBase + kUpb_FieldType_String] = kUpb_DecodeOp_String, + [kRepeatedBase + kUpb_FieldType_Group] = kUpb_DecodeOp_SubMessage, + [kRepeatedBase + kUpb_FieldType_Message] = kUpb_DecodeOp_SubMessage, + [kRepeatedBase + kUpb_FieldType_Bytes] = kUpb_DecodeOp_Bytes, + [kRepeatedBase + kUpb_FieldType_UInt32] = OP_VARPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Enum] = kUpb_DecodeOp_PackedEnum, + [kRepeatedBase + kUpb_FieldType_SFixed32] = OP_FIXPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_SFixed64] = OP_FIXPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_SInt32] = OP_VARPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_SInt64] = OP_VARPCK_LG2(3), + // Omitting kUpb_FakeFieldType_MessageSetItem, because we never emit a + // repeated msgset type + }; - if (seconds.int64_val < -max || seconds.int64_val > max) { - jsondec_err(d, "Duration out of range"); - } + int ndx = field->descriptortype; + if (upb_FieldMode_Get(field) == kUpb_FieldMode_Array) ndx += kRepeatedBase; + int op = kDelimitedOps[ndx]; - if (seconds.int64_val < 0) { - nanos.int32_val = -nanos.int32_val; + // If sub-message is not linked, treat as unknown. + if (op == kUpb_DecodeOp_SubMessage && + !(field->mode & kUpb_LabelFlags_IsExtension)) { + const upb_MiniTable_Sub* sub = &mt->subs[field->submsg_index]; + if (!sub->submsg) { + op = kUpb_DecodeOp_UnknownField; + } } - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, - d->arena); - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); + return op; } -static void jsondec_listvalue(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(values_f); - upb_Array* values = upb_Message_Mutable(msg, values_f, d->arena).array; +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeWireValue( + upb_Decoder* d, const char* ptr, const upb_MiniTable* mt, + const upb_MiniTable_Field* field, int wire_type, wireval* val, int* op) { + static const unsigned kFixed32OkMask = (1 << kUpb_FieldType_Float) | + (1 << kUpb_FieldType_Fixed32) | + (1 << kUpb_FieldType_SFixed32); - jsondec_arrstart(d); - while (jsondec_arrnext(d)) { - upb_Message* value_msg = upb_Message_New(value_m, d->arena); - upb_MessageValue value; - value.msg_val = value_msg; - upb_Array_Append(values, value, d->arena); - jsondec_wellknownvalue(d, value_msg, value_m); + static const unsigned kFixed64OkMask = (1 << kUpb_FieldType_Double) | + (1 << kUpb_FieldType_Fixed64) | + (1 << kUpb_FieldType_SFixed64); + + switch (wire_type) { + case kUpb_WireType_Varint: + ptr = _upb_Decoder_DecodeVarint(d, ptr, &val->uint64_val); + *op = _upb_Decoder_GetVarintOp(field); + _upb_Decoder_Munge(field->descriptortype, val); + return ptr; + case kUpb_WireType_32Bit: + memcpy(&val->uint32_val, ptr, 4); + val->uint32_val = _upb_BigEndian_Swap32(val->uint32_val); + *op = kUpb_DecodeOp_Scalar4Byte; + if (((1 << field->descriptortype) & kFixed32OkMask) == 0) { + *op = kUpb_DecodeOp_UnknownField; + } + return ptr + 4; + case kUpb_WireType_64Bit: + memcpy(&val->uint64_val, ptr, 8); + val->uint64_val = _upb_BigEndian_Swap64(val->uint64_val); + *op = kUpb_DecodeOp_Scalar8Byte; + if (((1 << field->descriptortype) & kFixed64OkMask) == 0) { + *op = kUpb_DecodeOp_UnknownField; + } + return ptr + 8; + case kUpb_WireType_Delimited: + ptr = upb_Decoder_DecodeSize(d, ptr, &val->size); + *op = _upb_Decoder_GetDelimitedOp(mt, field); + return ptr; + case kUpb_WireType_StartGroup: + val->uint32_val = field->number; + if (field->descriptortype == kUpb_FieldType_Group) { + *op = kUpb_DecodeOp_SubMessage; + } else if (field->descriptortype == kUpb_FakeFieldType_MessageSetItem) { + *op = kUpb_DecodeOp_MessageSetItem; + } else { + *op = kUpb_DecodeOp_UnknownField; + } + return ptr; + default: + break; } - jsondec_arrend(d); + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); } -static void jsondec_struct(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); - const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(value_f); - upb_Map* fields = upb_Message_Mutable(msg, fields_f, d->arena).map; +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeKnownField( + upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTable* layout, const upb_MiniTable_Field* field, int op, + wireval* val) { + const upb_MiniTable_Sub* subs = layout->subs; + uint8_t mode = field->mode; - jsondec_objstart(d); - while (jsondec_objnext(d)) { - upb_MessageValue key, value; - upb_Message* value_msg = upb_Message_New(value_m, d->arena); - key.str_val = jsondec_string(d); - value.msg_val = value_msg; - upb_Map_Set(fields, key, value, d->arena); - jsondec_entrysep(d); - jsondec_wellknownvalue(d, value_msg, value_m); + if (UPB_UNLIKELY(mode & kUpb_LabelFlags_IsExtension)) { + const upb_MiniTable_Extension* ext_layout = + (const upb_MiniTable_Extension*)field; + upb_Message_Extension* ext = + _upb_Message_GetOrCreateExtension(msg, ext_layout, &d->arena); + if (UPB_UNLIKELY(!ext)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + d->unknown_msg = msg; + msg = &ext->data; + subs = &ext->ext->sub; } - jsondec_objend(d); -} - -static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - upb_MessageValue val; - const upb_FieldDef* f; - upb_Message* submsg; - switch (jsondec_peek(d)) { - case JD_NUMBER: - /* double number_value = 2; */ - f = upb_MessageDef_FindFieldByNumber(m, 2); - val.double_val = jsondec_number(d); - break; - case JD_STRING: - /* string string_value = 3; */ - f = upb_MessageDef_FindFieldByNumber(m, 3); - val.str_val = jsondec_string(d); - break; - case JD_FALSE: - /* bool bool_value = 4; */ - f = upb_MessageDef_FindFieldByNumber(m, 4); - val.bool_val = false; - jsondec_false(d); - break; - case JD_TRUE: - /* bool bool_value = 4; */ - f = upb_MessageDef_FindFieldByNumber(m, 4); - val.bool_val = true; - jsondec_true(d); - break; - case JD_NULL: - /* NullValue null_value = 1; */ - f = upb_MessageDef_FindFieldByNumber(m, 1); - val.int32_val = 0; - jsondec_null(d); - break; - /* Note: these cases return, because upb_Message_Mutable() is enough. */ - case JD_OBJECT: - /* Struct struct_value = 5; */ - f = upb_MessageDef_FindFieldByNumber(m, 5); - submsg = upb_Message_Mutable(msg, f, d->arena).msg; - jsondec_struct(d, submsg, upb_FieldDef_MessageSubDef(f)); - return; - case JD_ARRAY: - /* ListValue list_value = 6; */ - f = upb_MessageDef_FindFieldByNumber(m, 6); - submsg = upb_Message_Mutable(msg, f, d->arena).msg; - jsondec_listvalue(d, submsg, upb_FieldDef_MessageSubDef(f)); - return; + switch (mode & kUpb_FieldMode_Mask) { + case kUpb_FieldMode_Array: + return _upb_Decoder_DecodeToArray(d, ptr, msg, subs, field, val, op); + case kUpb_FieldMode_Map: + return _upb_Decoder_DecodeToMap(d, ptr, msg, subs, field, val); + case kUpb_FieldMode_Scalar: + return _upb_Decoder_DecodeToSubMessage(d, ptr, msg, subs, field, val, op); default: UPB_UNREACHABLE(); } +} - upb_Message_Set(msg, f, val, d->arena); +static const char* _upb_Decoder_ReverseSkipVarint(const char* ptr, + uint32_t val) { + uint32_t seen = 0; + do { + ptr--; + seen <<= 7; + seen |= *ptr & 0x7f; + } while (seen != val); + return ptr; } -static upb_StringView jsondec_mask(jsondec* d, const char* buf, - const char* end) { - /* FieldMask fields grow due to inserted '_' characters, so we can't do the - * transform in place. */ - const char* ptr = buf; - upb_StringView ret; - char* out; +static const char* _upb_Decoder_DecodeUnknownField(upb_Decoder* d, + const char* ptr, + upb_Message* msg, + int field_number, + int wire_type, wireval val) { + if (field_number == 0) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); - ret.size = end - ptr; - while (ptr < end) { - ret.size += (*ptr >= 'A' && *ptr <= 'Z'); - ptr++; + // Since unknown fields are the uncommon case, we do a little extra work here + // to walk backwards through the buffer to find the field start. This frees + // up a register in the fast paths (when the field is known), which leads to + // significant speedups in benchmarks. + const char* start = ptr; + + if (wire_type == kUpb_WireType_Delimited) ptr += val.size; + if (msg) { + switch (wire_type) { + case kUpb_WireType_Varint: + case kUpb_WireType_Delimited: + start--; + while (start[-1] & 0x80) start--; + break; + case kUpb_WireType_32Bit: + start -= 4; + break; + case kUpb_WireType_64Bit: + start -= 8; + break; + default: + break; + } + + assert(start == d->debug_valstart); + uint32_t tag = ((uint32_t)field_number << 3) | wire_type; + start = _upb_Decoder_ReverseSkipVarint(start, tag); + assert(start == d->debug_tagstart); + + if (wire_type == kUpb_WireType_StartGroup) { + d->unknown = start; + d->unknown_msg = msg; + ptr = _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); + start = d->unknown; + d->unknown = NULL; + } + if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + } else if (wire_type == kUpb_WireType_StartGroup) { + ptr = _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); } + return ptr; +} - out = upb_Arena_Malloc(d->arena, ret.size); - ptr = buf; - ret.data = out; +UPB_NOINLINE +static const char* _upb_Decoder_DecodeMessage(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable* layout) { + int last_field_index = 0; - while (ptr < end) { - char ch = *ptr++; - if (ch >= 'A' && ch <= 'Z') { - *out++ = '_'; - *out++ = ch + 32; - } else if (ch == '_') { - jsondec_err(d, "field mask may not contain '_'"); +#if UPB_FASTTABLE + // The first time we want to skip fast dispatch, because we may have just been + // invoked by the fast parser to handle a case that it bailed on. + if (!_upb_Decoder_IsDone(d, &ptr)) goto nofast; +#endif + + while (!_upb_Decoder_IsDone(d, &ptr)) { + uint32_t tag; + const upb_MiniTable_Field* field; + int field_number; + int wire_type; + wireval val; + int op; + + if (_upb_Decoder_TryFastDispatch(d, &ptr, msg, layout)) break; + +#if UPB_FASTTABLE + nofast: +#endif + +#ifndef NDEBUG + d->debug_tagstart = ptr; +#endif + + UPB_ASSERT(ptr < d->limit_ptr); + ptr = _upb_Decoder_DecodeTag(d, ptr, &tag); + field_number = tag >> 3; + wire_type = tag & 7; + +#ifndef NDEBUG + d->debug_valstart = ptr; +#endif + + if (wire_type == kUpb_WireType_EndGroup) { + d->end_group = field_number; + return ptr; + } + + field = _upb_Decoder_FindField(d, layout, field_number, &last_field_index); + ptr = _upb_Decoder_DecodeWireValue(d, ptr, layout, field, wire_type, &val, + &op); + + if (op >= 0) { + ptr = _upb_Decoder_DecodeKnownField(d, ptr, msg, layout, field, op, &val); } else { - *out++ = ch; + switch (op) { + case kUpb_DecodeOp_UnknownField: + ptr = _upb_Decoder_DecodeUnknownField(d, ptr, msg, field_number, + wire_type, val); + break; + case kUpb_DecodeOp_MessageSetItem: + ptr = upb_Decoder_DecodeMessageSetItem(d, ptr, msg, layout); + break; + } } } - return ret; + return UPB_UNLIKELY(layout && layout->required_count) + ? _upb_Decoder_CheckRequired(d, ptr, msg, layout) + : ptr; } -static void jsondec_fieldmask(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - /* repeated string paths = 1; */ - const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); - upb_Array* arr = upb_Message_Mutable(msg, paths_f, d->arena).array; - upb_StringView str = jsondec_string(d); - const char* ptr = str.data; - const char* end = ptr + str.size; - upb_MessageValue val; - - while (ptr < end) { - const char* elem_end = memchr(ptr, ',', end - ptr); - if (elem_end) { - val.str_val = jsondec_mask(d, ptr, elem_end); - ptr = elem_end + 1; - } else { - val.str_val = jsondec_mask(d, ptr, end); - ptr = end; - } - upb_Array_Append(arr, val, d->arena); - } +const char* _upb_FastDecoder_DecodeGeneric(struct upb_Decoder* d, + const char* ptr, upb_Message* msg, + intptr_t table, uint64_t hasbits, + uint64_t data) { + (void)data; + *(uint32_t*)msg |= hasbits; + return _upb_Decoder_DecodeMessage(d, ptr, msg, decode_totablep(table)); } -static void jsondec_anyfield(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { - /* For regular types: {"@type": "[user type]", "f1": , "f2": } - * where f1, f2, etc. are the normal fields of this type. */ - jsondec_field(d, msg, m); - } else { - /* For well-known types: {"@type": "[well-known type]", "value": } - * where is whatever encoding the WKT normally uses. */ - upb_StringView str = jsondec_string(d); - jsondec_entrysep(d); - if (!jsondec_streql(str, "value")) { - jsondec_err(d, "Key for well-known type must be 'value'"); - } - jsondec_wellknown(d, msg, m); +static upb_DecodeStatus _upb_Decoder_DecodeTop(struct upb_Decoder* d, + const char* buf, void* msg, + const upb_MiniTable* l) { + if (!_upb_Decoder_TryFastDispatch(d, &buf, msg, l)) { + _upb_Decoder_DecodeMessage(d, buf, msg, l); } + if (d->end_group != DECODE_NOGROUP) return kUpb_DecodeStatus_Malformed; + if (d->missing_required) return kUpb_DecodeStatus_MissingRequired; + return kUpb_DecodeStatus_Ok; } -static const upb_MessageDef* jsondec_typeurl(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_MessageDef* type_m; - upb_StringView type_url = jsondec_string(d); - const char* end = type_url.data + type_url.size; - const char* ptr = end; - upb_MessageValue val; - - val.str_val = type_url; - upb_Message_Set(msg, type_url_f, val, d->arena); - - /* Find message name after the last '/' */ - while (ptr > type_url.data && *--ptr != '/') { - } +upb_DecodeStatus upb_Decode(const char* buf, size_t size, void* msg, + const upb_MiniTable* l, + const upb_ExtensionRegistry* extreg, int options, + upb_Arena* arena) { + upb_Decoder state; + unsigned depth = (unsigned)options >> 16; - if (ptr == type_url.data || ptr == end) { - jsondec_err(d, "Type url must have at least one '/' and non-empty host"); + if (size <= 16) { + memset(&state.patch, 0, 32); + if (size) memcpy(&state.patch, buf, size); + buf = state.patch; + state.end = buf + size; + state.limit = 0; + options &= ~kUpb_DecodeOption_AliasString; // Can't alias patch buf. + } else { + state.end = buf + size - 16; + state.limit = 16; } - ptr++; - type_m = upb_DefPool_FindMessageByNameWithSize(d->symtab, ptr, end - ptr); + state.extreg = extreg; + state.limit_ptr = state.end; + state.unknown = NULL; + state.depth = depth ? depth : 64; + state.end_group = DECODE_NOGROUP; + state.options = (uint16_t)options; + state.missing_required = false; + state.arena.head = arena->head; + state.arena.last_size = arena->last_size; + state.arena.cleanup_metadata = arena->cleanup_metadata; + state.arena.parent = arena; - if (!type_m) { - jsondec_err(d, "Type was not found"); + upb_DecodeStatus status = UPB_SETJMP(state.err); + if (UPB_LIKELY(status == kUpb_DecodeStatus_Ok)) { + status = _upb_Decoder_DecodeTop(&state, buf, msg, l); } - return type_m; + arena->head.ptr = state.arena.head.ptr; + arena->head.end = state.arena.head.end; + arena->cleanup_metadata = state.arena.cleanup_metadata; + return status; } -static void jsondec_any(jsondec* d, upb_Message* msg, const upb_MessageDef* m) { - /* string type_url = 1; - * bytes value = 2; */ - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); - upb_Message* any_msg; - const upb_MessageDef* any_m = NULL; - const char* pre_type_data = NULL; - const char* pre_type_end = NULL; - upb_MessageValue encoded; - - jsondec_objstart(d); +#undef OP_FIXPCK_LG2 +#undef OP_VARPCK_LG2 - /* Scan looking for "@type", which is not necessarily first. */ - while (!any_m && jsondec_objnext(d)) { - const char* start = d->ptr; - upb_StringView name = jsondec_string(d); - jsondec_entrysep(d); - if (jsondec_streql(name, "@type")) { - any_m = jsondec_typeurl(d, msg, m); - if (pre_type_data) { - pre_type_end = start; - while (*pre_type_end != ',') pre_type_end--; - } - } else { - if (!pre_type_data) pre_type_data = start; - jsondec_skipval(d); - } - } +/* We encode backwards, to avoid pre-computing lengths (one-pass encode). */ - if (!any_m) { - jsondec_err(d, "Any object didn't contain a '@type' field"); - } - any_msg = upb_Message_New(any_m, d->arena); +#include - if (pre_type_data) { - size_t len = pre_type_end - pre_type_data + 1; - char* tmp = upb_Arena_Malloc(d->arena, len); - const char* saved_ptr = d->ptr; - const char* saved_end = d->end; - memcpy(tmp, pre_type_data, len - 1); - tmp[len - 1] = '}'; - d->ptr = tmp; - d->end = tmp + len; - d->is_first = true; - while (jsondec_objnext(d)) { - jsondec_anyfield(d, any_msg, any_m); - } - d->ptr = saved_ptr; - d->end = saved_end; - } - while (jsondec_objnext(d)) { - jsondec_anyfield(d, any_msg, any_m); - } +// Must be last. - jsondec_objend(d); +#define UPB_PB_VARINT_MAX_LEN 10 - encoded.str_val.data = upb_Encode(any_msg, upb_MessageDef_MiniTable(any_m), 0, - d->arena, &encoded.str_val.size); - upb_Message_Set(msg, value_f, encoded, d->arena); +UPB_NOINLINE +static size_t encode_varint64(uint64_t val, char* buf) { + size_t i = 0; + do { + uint8_t byte = val & 0x7fU; + val >>= 7; + if (val) byte |= 0x80U; + buf[i++] = byte; + } while (val); + return i; } -static void jsondec_wrapper(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 1); - upb_MessageValue val = jsondec_value(d, value_f); - upb_Message_Set(msg, value_f, val, d->arena); +static uint32_t encode_zz32(int32_t n) { + return ((uint32_t)n << 1) ^ (n >> 31); +} +static uint64_t encode_zz64(int64_t n) { + return ((uint64_t)n << 1) ^ (n >> 63); } -static void jsondec_wellknown(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - switch (upb_MessageDef_WellKnownType(m)) { - case kUpb_WellKnown_Any: - jsondec_any(d, msg, m); - break; - case kUpb_WellKnown_FieldMask: - jsondec_fieldmask(d, msg, m); - break; - case kUpb_WellKnown_Duration: - jsondec_duration(d, msg, m); - break; - case kUpb_WellKnown_Timestamp: - jsondec_timestamp(d, msg, m); - break; - case kUpb_WellKnown_Value: - jsondec_wellknownvalue(d, msg, m); - break; - case kUpb_WellKnown_ListValue: - jsondec_listvalue(d, msg, m); - break; - case kUpb_WellKnown_Struct: - jsondec_struct(d, msg, m); - break; - case kUpb_WellKnown_DoubleValue: - case kUpb_WellKnown_FloatValue: - case kUpb_WellKnown_Int64Value: - case kUpb_WellKnown_UInt64Value: - case kUpb_WellKnown_Int32Value: - case kUpb_WellKnown_UInt32Value: - case kUpb_WellKnown_StringValue: - case kUpb_WellKnown_BytesValue: - case kUpb_WellKnown_BoolValue: - jsondec_wrapper(d, msg, m); - break; - default: - UPB_UNREACHABLE(); +typedef struct { + jmp_buf err; + upb_Arena* arena; + char *buf, *ptr, *limit; + int options; + int depth; + _upb_mapsorter sorter; +} upb_encstate; + +static size_t upb_roundup_pow2(size_t bytes) { + size_t ret = 128; + while (ret < bytes) { + ret *= 2; } + return ret; } -bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, - const upb_MessageDef* m, const upb_DefPool* symtab, - int options, upb_Arena* arena, upb_Status* status) { - jsondec d; +UPB_NORETURN static void encode_err(upb_encstate* e, upb_EncodeStatus s) { + UPB_LONGJMP(e->err, s); +} - if (size == 0) return true; +UPB_NOINLINE +static void encode_growbuffer(upb_encstate* e, size_t bytes) { + size_t old_size = e->limit - e->buf; + size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr)); + char* new_buf = upb_Arena_Realloc(e->arena, e->buf, old_size, new_size); - d.ptr = buf; - d.end = buf + size; - d.arena = arena; - d.symtab = symtab; - d.status = status; - d.options = options; - d.depth = 64; - d.line = 1; - d.line_begin = d.ptr; - d.debug_field = NULL; - d.is_first = false; + if (!new_buf) encode_err(e, kUpb_EncodeStatus_OutOfMemory); + + // We want previous data at the end, realloc() put it at the beginning. + // TODO(salo): This is somewhat inefficient since we are copying twice. + // Maybe create a realloc() that copies to the end of the new buffer? + if (old_size > 0) { + memmove(new_buf + new_size - old_size, e->buf, old_size); + } - if (UPB_SETJMP(d.err)) return false; + e->ptr = new_buf + new_size - (e->limit - e->ptr); + e->limit = new_buf + new_size; + e->buf = new_buf; - jsondec_tomsg(&d, msg, m); - return true; + e->ptr -= bytes; } -/** upb/json_encode.c ************************************************************/ +/* Call to ensure that at least "bytes" bytes are available for writing at + * e->ptr. Returns false if the bytes could not be allocated. */ +UPB_FORCEINLINE +static void encode_reserve(upb_encstate* e, size_t bytes) { + if ((size_t)(e->ptr - e->buf) < bytes) { + encode_growbuffer(e, bytes); + return; + } -#include -#include -#include -#include -#include -#include -#include -#include + e->ptr -= bytes; +} +/* Writes the given bytes to the buffer, handling reserve/advance. */ +static void encode_bytes(upb_encstate* e, const void* data, size_t len) { + if (len == 0) return; /* memcpy() with zero size is UB */ + encode_reserve(e, len); + memcpy(e->ptr, data, len); +} -/* Must be last. */ +static void encode_fixed64(upb_encstate* e, uint64_t val) { + val = _upb_BigEndian_Swap64(val); + encode_bytes(e, &val, sizeof(uint64_t)); +} -typedef struct { - char *buf, *ptr, *end; - size_t overflow; - int indent_depth; - int options; - const upb_DefPool* ext_pool; - jmp_buf err; - upb_Status* status; - upb_Arena* arena; -} jsonenc; +static void encode_fixed32(upb_encstate* e, uint32_t val) { + val = _upb_BigEndian_Swap32(val); + encode_bytes(e, &val, sizeof(uint32_t)); +} -static void jsonenc_msg(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m); -static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, - const upb_FieldDef* f); -static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m); -static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m, bool first); -static void jsonenc_value(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m); +UPB_NOINLINE +static void encode_longvarint(upb_encstate* e, uint64_t val) { + size_t len; + char* start; -UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) { - upb_Status_SetErrorMessage(e->status, msg); - longjmp(e->err, 1); + encode_reserve(e, UPB_PB_VARINT_MAX_LEN); + len = encode_varint64(val, e->ptr); + start = e->ptr + UPB_PB_VARINT_MAX_LEN - len; + memmove(start, e->ptr, len); + e->ptr = start; } -UPB_PRINTF(2, 3) -UPB_NORETURN static void jsonenc_errf(jsonenc* e, const char* fmt, ...) { - va_list argp; - va_start(argp, fmt); - upb_Status_VSetErrorFormat(e->status, fmt, argp); - va_end(argp); - longjmp(e->err, 1); +UPB_FORCEINLINE +static void encode_varint(upb_encstate* e, uint64_t val) { + if (val < 128 && e->ptr != e->buf) { + --e->ptr; + *e->ptr = val; + } else { + encode_longvarint(e, val); + } } -static upb_Arena* jsonenc_arena(jsonenc* e) { - /* Create lazily, since it's only needed for Any */ - if (!e->arena) { - e->arena = upb_Arena_New(); - } - return e->arena; +static void encode_double(upb_encstate* e, double d) { + uint64_t u64; + UPB_ASSERT(sizeof(double) == sizeof(uint64_t)); + memcpy(&u64, &d, sizeof(uint64_t)); + encode_fixed64(e, u64); } -static void jsonenc_putbytes(jsonenc* e, const void* data, size_t len) { - size_t have = e->end - e->ptr; - if (UPB_LIKELY(have >= len)) { - memcpy(e->ptr, data, len); - e->ptr += len; - } else { - if (have) { - memcpy(e->ptr, data, have); - e->ptr += have; - } - e->overflow += (len - have); - } +static void encode_float(upb_encstate* e, float d) { + uint32_t u32; + UPB_ASSERT(sizeof(float) == sizeof(uint32_t)); + memcpy(&u32, &d, sizeof(uint32_t)); + encode_fixed32(e, u32); } -static void jsonenc_putstr(jsonenc* e, const char* str) { - jsonenc_putbytes(e, str, strlen(str)); +static void encode_tag(upb_encstate* e, uint32_t field_number, + uint8_t wire_type) { + encode_varint(e, (field_number << 3) | wire_type); } -UPB_PRINTF(2, 3) -static void jsonenc_printf(jsonenc* e, const char* fmt, ...) { - size_t n; - size_t have = e->end - e->ptr; - va_list args; +static void encode_fixedarray(upb_encstate* e, const upb_Array* arr, + size_t elem_size, uint32_t tag) { + size_t bytes = arr->size * elem_size; + const char* data = _upb_array_constptr(arr); + const char* ptr = data + bytes - elem_size; - va_start(args, fmt); - n = vsnprintf(e->ptr, have, fmt, args); - va_end(args); + if (tag || !_upb_IsLittleEndian()) { + while (true) { + if (elem_size == 4) { + uint32_t val; + memcpy(&val, ptr, sizeof(val)); + val = _upb_BigEndian_Swap32(val); + encode_bytes(e, &val, elem_size); + } else { + UPB_ASSERT(elem_size == 8); + uint64_t val; + memcpy(&val, ptr, sizeof(val)); + val = _upb_BigEndian_Swap64(val); + encode_bytes(e, &val, elem_size); + } - if (UPB_LIKELY(have > n)) { - e->ptr += n; + if (tag) encode_varint(e, tag); + if (ptr == data) break; + ptr -= elem_size; + } } else { - e->ptr = UPB_PTRADD(e->ptr, have); - e->overflow += (n - have); + encode_bytes(e, data, bytes); } } -static void jsonenc_nanos(jsonenc* e, int32_t nanos) { - int digits = 9; +static void encode_message(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable* m, size_t* size); - if (nanos == 0) return; - if (nanos < 0 || nanos >= 1000000000) { - jsonenc_err(e, "error formatting timestamp as JSON: invalid nanos"); - } +static void encode_scalar(upb_encstate* e, const void* _field_mem, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* f) { + const char* field_mem = _field_mem; + int wire_type; - while (nanos % 1000 == 0) { - nanos /= 1000; - digits -= 3; +#define CASE(ctype, type, wtype, encodeval) \ + { \ + ctype val = *(ctype*)field_mem; \ + encode_##type(e, encodeval); \ + wire_type = wtype; \ + break; \ } - jsonenc_printf(e, ".%.*" PRId32, digits, nanos); -} - -static void jsonenc_timestamp(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); - int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; - int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; - int L, N, I, J, K, hour, min, sec; - - if (seconds < -62135596800) { - jsonenc_err(e, - "error formatting timestamp as JSON: minimum acceptable value " - "is 0001-01-01T00:00:00Z"); - } else if (seconds > 253402300799) { - jsonenc_err(e, - "error formatting timestamp as JSON: maximum acceptable value " - "is 9999-12-31T23:59:59Z"); + switch (f->descriptortype) { + case kUpb_FieldType_Double: + CASE(double, double, kUpb_WireType_64Bit, val); + case kUpb_FieldType_Float: + CASE(float, float, kUpb_WireType_32Bit, val); + case kUpb_FieldType_Int64: + case kUpb_FieldType_UInt64: + CASE(uint64_t, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_UInt32: + CASE(uint32_t, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_Int32: + case kUpb_FieldType_Enum: + CASE(int32_t, varint, kUpb_WireType_Varint, (int64_t)val); + case kUpb_FieldType_SFixed64: + case kUpb_FieldType_Fixed64: + CASE(uint64_t, fixed64, kUpb_WireType_64Bit, val); + case kUpb_FieldType_Fixed32: + case kUpb_FieldType_SFixed32: + CASE(uint32_t, fixed32, kUpb_WireType_32Bit, val); + case kUpb_FieldType_Bool: + CASE(bool, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_SInt32: + CASE(int32_t, varint, kUpb_WireType_Varint, encode_zz32(val)); + case kUpb_FieldType_SInt64: + CASE(int64_t, varint, kUpb_WireType_Varint, encode_zz64(val)); + case kUpb_FieldType_String: + case kUpb_FieldType_Bytes: { + upb_StringView view = *(upb_StringView*)field_mem; + encode_bytes(e, view.data, view.size); + encode_varint(e, view.size); + wire_type = kUpb_WireType_Delimited; + break; + } + case kUpb_FieldType_Group: { + size_t size; + void* submsg = *(void**)field_mem; + const upb_MiniTable* subm = subs[f->submsg_index].submsg; + if (submsg == NULL) { + return; + } + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + encode_tag(e, f->number, kUpb_WireType_EndGroup); + encode_message(e, submsg, subm, &size); + wire_type = kUpb_WireType_StartGroup; + e->depth++; + break; + } + case kUpb_FieldType_Message: { + size_t size; + void* submsg = *(void**)field_mem; + const upb_MiniTable* subm = subs[f->submsg_index].submsg; + if (submsg == NULL) { + return; + } + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + encode_message(e, submsg, subm, &size); + encode_varint(e, size); + wire_type = kUpb_WireType_Delimited; + e->depth++; + break; + } + default: + UPB_UNREACHABLE(); } +#undef CASE - /* Julian Day -> Y/M/D, Algorithm from: - * Fliegel, H. F., and Van Flandern, T. C., "A Machine Algorithm for - * Processing Calendar Dates," Communications of the Association of - * Computing Machines, vol. 11 (1968), p. 657. */ - seconds += 62135596800; // Ensure seconds is positive. - L = (int)(seconds / 86400) - 719162 + 68569 + 2440588; - N = 4 * L / 146097; - L = L - (146097 * N + 3) / 4; - I = 4000 * (L + 1) / 1461001; - L = L - 1461 * I / 4 + 31; - J = 80 * L / 2447; - K = L - 2447 * J / 80; - L = J / 11; - J = J + 2 - 12 * L; - I = 100 * (N - 49) + I + L; - - sec = seconds % 60; - min = (seconds / 60) % 60; - hour = (seconds / 3600) % 24; - - jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec); - jsonenc_nanos(e, nanos); - jsonenc_putstr(e, "Z\""); + encode_tag(e, f->number, wire_type); } -static void jsonenc_duration(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); - int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; - int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; - - if (seconds > 315576000000 || seconds < -315576000000 || - (seconds < 0) != (nanos < 0)) { - jsonenc_err(e, "bad duration"); - } +static void encode_array(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* f) { + const upb_Array* arr = *UPB_PTR_AT(msg, f->offset, upb_Array*); + bool packed = f->mode & kUpb_LabelFlags_IsPacked; + size_t pre_len = e->limit - e->ptr; - if (nanos < 0) { - nanos = -nanos; + if (arr == NULL || arr->size == 0) { + return; } - jsonenc_printf(e, "\"%" PRId64, seconds); - jsonenc_nanos(e, nanos); - jsonenc_putstr(e, "s\""); -} - -static void jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) { - const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f); +#define VARINT_CASE(ctype, encode) \ + { \ + const ctype* start = _upb_array_constptr(arr); \ + const ctype* ptr = start + arr->size; \ + uint32_t tag = packed ? 0 : (f->number << 3) | kUpb_WireType_Varint; \ + do { \ + ptr--; \ + encode_varint(e, encode); \ + if (tag) encode_varint(e, tag); \ + } while (ptr != start); \ + } \ + break; - if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) { - jsonenc_putstr(e, "null"); - } else { - const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNumber(e_def, val); +#define TAG(wire_type) (packed ? 0 : (f->number << 3 | wire_type)) - if (ev) { - jsonenc_printf(e, "\"%s\"", upb_EnumValueDef_Name(ev)); - } else { - jsonenc_printf(e, "%" PRId32, val); + switch (f->descriptortype) { + case kUpb_FieldType_Double: + encode_fixedarray(e, arr, sizeof(double), TAG(kUpb_WireType_64Bit)); + break; + case kUpb_FieldType_Float: + encode_fixedarray(e, arr, sizeof(float), TAG(kUpb_WireType_32Bit)); + break; + case kUpb_FieldType_SFixed64: + case kUpb_FieldType_Fixed64: + encode_fixedarray(e, arr, sizeof(uint64_t), TAG(kUpb_WireType_64Bit)); + break; + case kUpb_FieldType_Fixed32: + case kUpb_FieldType_SFixed32: + encode_fixedarray(e, arr, sizeof(uint32_t), TAG(kUpb_WireType_32Bit)); + break; + case kUpb_FieldType_Int64: + case kUpb_FieldType_UInt64: + VARINT_CASE(uint64_t, *ptr); + case kUpb_FieldType_UInt32: + VARINT_CASE(uint32_t, *ptr); + case kUpb_FieldType_Int32: + case kUpb_FieldType_Enum: + VARINT_CASE(int32_t, (int64_t)*ptr); + case kUpb_FieldType_Bool: + VARINT_CASE(bool, *ptr); + case kUpb_FieldType_SInt32: + VARINT_CASE(int32_t, encode_zz32(*ptr)); + case kUpb_FieldType_SInt64: + VARINT_CASE(int64_t, encode_zz64(*ptr)); + case kUpb_FieldType_String: + case kUpb_FieldType_Bytes: { + const upb_StringView* start = _upb_array_constptr(arr); + const upb_StringView* ptr = start + arr->size; + do { + ptr--; + encode_bytes(e, ptr->data, ptr->size); + encode_varint(e, ptr->size); + encode_tag(e, f->number, kUpb_WireType_Delimited); + } while (ptr != start); + return; + } + case kUpb_FieldType_Group: { + const void* const* start = _upb_array_constptr(arr); + const void* const* ptr = start + arr->size; + const upb_MiniTable* subm = subs[f->submsg_index].submsg; + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + do { + size_t size; + ptr--; + encode_tag(e, f->number, kUpb_WireType_EndGroup); + encode_message(e, *ptr, subm, &size); + encode_tag(e, f->number, kUpb_WireType_StartGroup); + } while (ptr != start); + e->depth++; + return; + } + case kUpb_FieldType_Message: { + const void* const* start = _upb_array_constptr(arr); + const void* const* ptr = start + arr->size; + const upb_MiniTable* subm = subs[f->submsg_index].submsg; + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + do { + size_t size; + ptr--; + encode_message(e, *ptr, subm, &size); + encode_varint(e, size); + encode_tag(e, f->number, kUpb_WireType_Delimited); + } while (ptr != start); + e->depth++; + return; } } -} - -static void jsonenc_bytes(jsonenc* e, upb_StringView str) { - /* This is the regular base64, not the "web-safe" version. */ - static const char base64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - const unsigned char* ptr = (unsigned char*)str.data; - const unsigned char* end = UPB_PTRADD(ptr, str.size); - char buf[4]; - - jsonenc_putstr(e, "\""); - - while (end - ptr >= 3) { - buf[0] = base64[ptr[0] >> 2]; - buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; - buf[2] = base64[((ptr[1] & 0xf) << 2) | (ptr[2] >> 6)]; - buf[3] = base64[ptr[2] & 0x3f]; - jsonenc_putbytes(e, buf, 4); - ptr += 3; - } +#undef VARINT_CASE - switch (end - ptr) { - case 2: - buf[0] = base64[ptr[0] >> 2]; - buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; - buf[2] = base64[(ptr[1] & 0xf) << 2]; - buf[3] = '='; - jsonenc_putbytes(e, buf, 4); - break; - case 1: - buf[0] = base64[ptr[0] >> 2]; - buf[1] = base64[((ptr[0] & 0x3) << 4)]; - buf[2] = '='; - buf[3] = '='; - jsonenc_putbytes(e, buf, 4); - break; + if (packed) { + encode_varint(e, e->limit - e->ptr - pre_len); + encode_tag(e, f->number, kUpb_WireType_Delimited); } +} - jsonenc_putstr(e, "\""); +static void encode_mapentry(upb_encstate* e, uint32_t number, + const upb_MiniTable* layout, + const upb_MapEntry* ent) { + const upb_MiniTable_Field* key_field = &layout->fields[0]; + const upb_MiniTable_Field* val_field = &layout->fields[1]; + size_t pre_len = e->limit - e->ptr; + size_t size; + encode_scalar(e, &ent->v, layout->subs, val_field); + encode_scalar(e, &ent->k, layout->subs, key_field); + size = (e->limit - e->ptr) - pre_len; + encode_varint(e, size); + encode_tag(e, number, kUpb_WireType_Delimited); } -static void jsonenc_stringbody(jsonenc* e, upb_StringView str) { - const char* ptr = str.data; - const char* end = UPB_PTRADD(ptr, str.size); +static void encode_map(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* f) { + const upb_Map* map = *UPB_PTR_AT(msg, f->offset, const upb_Map*); + const upb_MiniTable* layout = subs[f->submsg_index].submsg; + UPB_ASSERT(layout->field_count == 2); - while (ptr < end) { - switch (*ptr) { - case '\n': - jsonenc_putstr(e, "\\n"); - break; - case '\r': - jsonenc_putstr(e, "\\r"); - break; - case '\t': - jsonenc_putstr(e, "\\t"); - break; - case '\"': - jsonenc_putstr(e, "\\\""); - break; - case '\f': - jsonenc_putstr(e, "\\f"); - break; - case '\b': - jsonenc_putstr(e, "\\b"); - break; - case '\\': - jsonenc_putstr(e, "\\\\"); - break; - default: - if ((uint8_t)*ptr < 0x20) { - jsonenc_printf(e, "\\u%04x", (int)(uint8_t)*ptr); - } else { - /* This could be a non-ASCII byte. We rely on the string being valid - * UTF-8. */ - jsonenc_putbytes(e, ptr, 1); - } - break; - } - ptr++; - } -} + if (map == NULL) return; -static void jsonenc_string(jsonenc* e, upb_StringView str) { - jsonenc_putstr(e, "\""); - jsonenc_stringbody(e, str); - jsonenc_putstr(e, "\""); + if (e->options & kUpb_EncodeOption_Deterministic) { + _upb_sortedmap sorted; + _upb_mapsorter_pushmap(&e->sorter, layout->fields[0].descriptortype, map, + &sorted); + upb_MapEntry ent; + while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) { + encode_mapentry(e, f->number, layout, &ent); + } + _upb_mapsorter_popmap(&e->sorter, &sorted); + } else { + upb_strtable_iter i; + upb_strtable_begin(&i, &map->table); + for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { + upb_StringView key = upb_strtable_iter_key(&i); + const upb_value val = upb_strtable_iter_value(&i); + upb_MapEntry ent; + _upb_map_fromkey(key, &ent.k, map->key_size); + _upb_map_fromvalue(val, &ent.v, map->val_size); + encode_mapentry(e, f->number, layout, &ent); + } + } } -static bool upb_JsonEncode_HandleSpecialDoubles(jsonenc* e, double val) { - if (val == INFINITY) { - jsonenc_putstr(e, "\"Infinity\""); - } else if (val == -INFINITY) { - jsonenc_putstr(e, "\"-Infinity\""); - } else if (val != val) { - jsonenc_putstr(e, "\"NaN\""); +static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* f) { + if (f->presence == 0) { + /* Proto3 presence or map/array. */ + const void* mem = UPB_PTR_AT(msg, f->offset, void); + switch (f->mode >> kUpb_FieldRep_Shift) { + case kUpb_FieldRep_1Byte: { + char ch; + memcpy(&ch, mem, 1); + return ch != 0; + } +#if UINTPTR_MAX == 0xffffffff + case kUpb_FieldRep_Pointer: +#endif + case kUpb_FieldRep_4Byte: { + uint32_t u32; + memcpy(&u32, mem, 4); + return u32 != 0; + } +#if UINTPTR_MAX != 0xffffffff + case kUpb_FieldRep_Pointer: +#endif + case kUpb_FieldRep_8Byte: { + uint64_t u64; + memcpy(&u64, mem, 8); + return u64 != 0; + } + case kUpb_FieldRep_StringView: { + const upb_StringView* str = (const upb_StringView*)mem; + return str->size != 0; + } + default: + UPB_UNREACHABLE(); + } + } else if (f->presence > 0) { + /* Proto2 presence: hasbit. */ + return _upb_hasbit_field(msg, f); } else { - return false; + /* Field is in a oneof. */ + return _upb_getoneofcase_field(msg, f) == f->number; } - return true; -} - -static void upb_JsonEncode_Double(jsonenc* e, double val) { - if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; - char buf[32]; - _upb_EncodeRoundTripDouble(val, buf, sizeof(buf)); - jsonenc_putstr(e, buf); } -static void upb_JsonEncode_Float(jsonenc* e, float val) { - if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; - char buf[32]; - _upb_EncodeRoundTripFloat(val, buf, sizeof(buf)); - jsonenc_putstr(e, buf); +static void encode_field(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field) { + switch (upb_FieldMode_Get(field)) { + case kUpb_FieldMode_Array: + encode_array(e, msg, subs, field); + break; + case kUpb_FieldMode_Map: + encode_map(e, msg, subs, field); + break; + case kUpb_FieldMode_Scalar: + encode_scalar(e, UPB_PTR_AT(msg, field->offset, void), subs, field); + break; + default: + UPB_UNREACHABLE(); + } } -static void jsonenc_wrapper(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(m, 1); - upb_MessageValue val = upb_Message_Get(msg, val_f); - jsonenc_scalar(e, val, val_f); +/* message MessageSet { + * repeated group Item = 1 { + * required int32 type_id = 2; + * required string message = 3; + * } + * } */ +static void encode_msgset_item(upb_encstate* e, + const upb_Message_Extension* ext) { + size_t size; + encode_tag(e, 1, kUpb_WireType_EndGroup); + encode_message(e, ext->data.ptr, ext->ext->sub.submsg, &size); + encode_varint(e, size); + encode_tag(e, 3, kUpb_WireType_Delimited); + encode_varint(e, ext->ext->field.number); + encode_tag(e, 2, kUpb_WireType_Varint); + encode_tag(e, 1, kUpb_WireType_StartGroup); } -static const upb_MessageDef* jsonenc_getanymsg(jsonenc* e, - upb_StringView type_url) { - /* Find last '/', if any. */ - const char* end = type_url.data + type_url.size; - const char* ptr = end; - const upb_MessageDef* ret; +static void encode_message(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable* m, size_t* size) { + size_t pre_len = e->limit - e->ptr; - if (!e->ext_pool) { - jsonenc_err(e, "Tried to encode Any, but no symtab was provided"); + if ((e->options & kUpb_EncodeOption_CheckRequired) && m->required_count) { + uint64_t msg_head; + memcpy(&msg_head, msg, 8); + msg_head = _upb_BigEndian_Swap64(msg_head); + if (upb_MiniTable_requiredmask(m) & ~msg_head) { + encode_err(e, kUpb_EncodeStatus_MissingRequired); + } } - if (type_url.size == 0) goto badurl; + if ((e->options & kUpb_EncodeOption_SkipUnknown) == 0) { + size_t unknown_size; + const char* unknown = upb_Message_GetUnknown(msg, &unknown_size); - while (true) { - if (--ptr == type_url.data) { - /* Type URL must contain at least one '/', with host before. */ - goto badurl; - } - if (*ptr == '/') { - ptr++; - break; + if (unknown) { + encode_bytes(e, unknown, unknown_size); } } - ret = upb_DefPool_FindMessageByNameWithSize(e->ext_pool, ptr, end - ptr); - - if (!ret) { - jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr); + if (m->ext != kUpb_ExtMode_NonExtendable) { + /* Encode all extensions together. Unlike C++, we do not attempt to keep + * these in field number order relative to normal fields or even to each + * other. */ + size_t ext_count; + const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &ext_count); + if (ext_count) { + const upb_Message_Extension* end = ext + ext_count; + for (; ext != end; ext++) { + if (UPB_UNLIKELY(m->ext == kUpb_ExtMode_IsMessageSet)) { + encode_msgset_item(e, ext); + } else { + encode_field(e, &ext->data, &ext->ext->sub, &ext->ext->field); + } + } + } } - return ret; + if (m->field_count) { + const upb_MiniTable_Field* f = &m->fields[m->field_count]; + const upb_MiniTable_Field* first = &m->fields[0]; + while (f != first) { + f--; + if (encode_shouldencode(e, msg, m->subs, f)) { + encode_field(e, msg, m->subs, f); + } + } + } -badurl: - jsonenc_errf(e, "Bad type URL: " UPB_STRINGVIEW_FORMAT, - UPB_STRINGVIEW_ARGS(type_url)); + *size = (e->limit - e->ptr) - pre_len; } -static void jsonenc_any(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); - upb_StringView type_url = upb_Message_Get(msg, type_url_f).str_val; - upb_StringView value = upb_Message_Get(msg, value_f).str_val; - const upb_MessageDef* any_m = jsonenc_getanymsg(e, type_url); - const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m); - upb_Arena* arena = jsonenc_arena(e); - upb_Message* any = upb_Message_New(any_m, arena); +upb_EncodeStatus upb_Encode(const void* msg, const upb_MiniTable* l, + int options, upb_Arena* arena, char** buf, + size_t* size) { + upb_encstate e; + unsigned depth = (unsigned)options >> 16; - if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) != - kUpb_DecodeStatus_Ok) { - jsonenc_err(e, "Error decoding message in Any"); - } + e.arena = arena; + e.buf = NULL; + e.limit = NULL; + e.ptr = NULL; + e.depth = depth ? depth : 64; + e.options = options; + _upb_mapsorter_init(&e.sorter); - jsonenc_putstr(e, "{\"@type\":"); - jsonenc_string(e, type_url); + upb_EncodeStatus status = UPB_SETJMP(e.err); - if (upb_MessageDef_WellKnownType(any_m) == kUpb_WellKnown_Unspecified) { - /* Regular messages: {"@type": "...","foo": 1, "bar": 2} */ - jsonenc_msgfields(e, any, any_m, false); + // Unfortunately we must continue to perform hackery here because there are + // code paths which blindly copy the returned pointer without bothering to + // check for errors until much later (b/235839510). So we still set *buf to + // NULL on error and we still set it to non-NULL on a successful empty result. + if (status == kUpb_EncodeStatus_Ok) { + encode_message(&e, msg, l, size); + *size = e.limit - e.ptr; + if (*size == 0) { + static char ch; + *buf = &ch; + } else { + UPB_ASSERT(e.ptr); + *buf = e.ptr; + } } else { - /* Well-known type: {"@type": "...","value": } */ - jsonenc_putstr(e, ",\"value\":"); - jsonenc_msgfield(e, any, any_m); + *buf = NULL; + *size = 0; } - jsonenc_putstr(e, "}"); + _upb_mapsorter_destroy(&e.sorter); + return status; } -static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) { - if (*first) { - *first = false; - } else { - jsonenc_putstr(e, str); - } + +// Must be last. + +static void _upb_mapsorter_getkeys(const void* _a, const void* _b, void* a_key, + void* b_key, size_t size) { + const upb_tabent* const* a = _a; + const upb_tabent* const* b = _b; + upb_StringView a_tabkey = upb_tabstrview((*a)->key); + upb_StringView b_tabkey = upb_tabstrview((*b)->key); + _upb_map_fromkey(a_tabkey, a_key, size); + _upb_map_fromkey(b_tabkey, b_key, size); } -static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) { - const char* ptr = path.data; - const char* end = ptr + path.size; +static int _upb_mapsorter_cmpi64(const void* _a, const void* _b) { + int64_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); + return a < b ? -1 : a > b; +} - while (ptr < end) { - char ch = *ptr; +static int _upb_mapsorter_cmpu64(const void* _a, const void* _b) { + uint64_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); + return a < b ? -1 : a > b; +} - if (ch >= 'A' && ch <= 'Z') { - jsonenc_err(e, "Field mask element may not have upper-case letter."); - } else if (ch == '_') { - if (ptr == end - 1 || *(ptr + 1) < 'a' || *(ptr + 1) > 'z') { - jsonenc_err(e, "Underscore must be followed by a lowercase letter."); - } - ch = *++ptr - 32; - } +static int _upb_mapsorter_cmpi32(const void* _a, const void* _b) { + int32_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); + return a < b ? -1 : a > b; +} + +static int _upb_mapsorter_cmpu32(const void* _a, const void* _b) { + uint32_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); + return a < b ? -1 : a > b; +} + +static int _upb_mapsorter_cmpbool(const void* _a, const void* _b) { + bool a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 1); + return a < b ? -1 : a > b; +} - jsonenc_putbytes(e, &ch, 1); - ptr++; - } +static int _upb_mapsorter_cmpstr(const void* _a, const void* _b) { + upb_StringView a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, UPB_MAPTYPE_STRING); + size_t common_size = UPB_MIN(a.size, b.size); + int cmp = memcmp(a.data, b.data, common_size); + if (cmp) return -cmp; + return a.size < b.size ? -1 : a.size > b.size; } -static void jsonenc_fieldmask(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_Array* paths = upb_Message_Get(msg, paths_f).array_val; - bool first = true; - size_t i, n = 0; +static int (*const compar[kUpb_FieldType_SizeOf])(const void*, const void*) = { + [kUpb_FieldType_Int64] = _upb_mapsorter_cmpi64, + [kUpb_FieldType_SFixed64] = _upb_mapsorter_cmpi64, + [kUpb_FieldType_SInt64] = _upb_mapsorter_cmpi64, - if (paths) n = upb_Array_Size(paths); + [kUpb_FieldType_UInt64] = _upb_mapsorter_cmpu64, + [kUpb_FieldType_Fixed64] = _upb_mapsorter_cmpu64, - jsonenc_putstr(e, "\""); + [kUpb_FieldType_Int32] = _upb_mapsorter_cmpi32, + [kUpb_FieldType_SInt32] = _upb_mapsorter_cmpi32, + [kUpb_FieldType_SFixed32] = _upb_mapsorter_cmpi32, + [kUpb_FieldType_Enum] = _upb_mapsorter_cmpi32, - for (i = 0; i < n; i++) { - jsonenc_putsep(e, ",", &first); - jsonenc_fieldpath(e, upb_Array_Get(paths, i).str_val); - } + [kUpb_FieldType_UInt32] = _upb_mapsorter_cmpu32, + [kUpb_FieldType_Fixed32] = _upb_mapsorter_cmpu32, - jsonenc_putstr(e, "\""); -} + [kUpb_FieldType_Bool] = _upb_mapsorter_cmpbool, -static void jsonenc_struct(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_Map* fields = upb_Message_Get(msg, fields_f).map_val; - const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); - size_t iter = kUpb_Map_Begin; - bool first = true; + [kUpb_FieldType_String] = _upb_mapsorter_cmpstr, + [kUpb_FieldType_Bytes] = _upb_mapsorter_cmpstr, +}; - jsonenc_putstr(e, "{"); +bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, + const upb_Map* map, _upb_sortedmap* sorted) { + int map_size = _upb_Map_Size(map); + sorted->start = s->size; + sorted->pos = sorted->start; + sorted->end = sorted->start + map_size; - if (fields) { - while (upb_MapIterator_Next(fields, &iter)) { - upb_MessageValue key = upb_MapIterator_Key(fields, iter); - upb_MessageValue val = upb_MapIterator_Value(fields, iter); + // Grow s->entries if necessary. + if (sorted->end > s->cap) { + s->cap = _upb_Log2CeilingSize(sorted->end); + s->entries = realloc(s->entries, s->cap * sizeof(*s->entries)); + if (!s->entries) return false; + } - jsonenc_putsep(e, ",", &first); - jsonenc_string(e, key.str_val); - jsonenc_putstr(e, ":"); - jsonenc_value(e, val.msg_val, upb_FieldDef_MessageSubDef(value_f)); + s->size = sorted->end; + + // Copy non-empty entries from the table to s->entries. + upb_tabent const** dst = &s->entries[sorted->start]; + const upb_tabent* src = map->table.t.entries; + const upb_tabent* end = src + upb_table_size(&map->table.t); + for (; src < end; src++) { + if (!upb_tabent_isempty(src)) { + *dst = src; + dst++; } } + UPB_ASSERT(dst == &s->entries[sorted->end]); - jsonenc_putstr(e, "}"); + // Sort entries according to the key type. + qsort(&s->entries[sorted->start], map_size, sizeof(*s->entries), + compar[key_type]); + return true; } -static void jsonenc_listvalue(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_MessageDef* values_m = upb_FieldDef_MessageSubDef(values_f); - const upb_Array* values = upb_Message_Get(msg, values_f).array_val; - size_t i; - bool first = true; - jsonenc_putstr(e, "["); +#include - if (values) { - const size_t size = upb_Array_Size(values); - for (i = 0; i < size; i++) { - upb_MessageValue elem = upb_Array_Get(values, i); - jsonenc_putsep(e, ",", &first); - jsonenc_value(e, elem.msg_val, values_m); - } - } +// Must be last. - jsonenc_putstr(e, "]"); +/** upb_Message ***************************************************************/ + +static const size_t overhead = sizeof(upb_Message_InternalData); + +static const upb_Message_Internal* upb_Message_Getinternal_const( + const upb_Message* msg) { + ptrdiff_t size = sizeof(upb_Message_Internal); + return (upb_Message_Internal*)((char*)msg - size); } -static void jsonenc_value(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - /* TODO(haberman): do we want a reflection method to get oneof case? */ - size_t iter = kUpb_Message_Begin; - const upb_FieldDef* f; - upb_MessageValue val; +upb_Message* _upb_Message_New(const upb_MiniTable* l, upb_Arena* a) { + return _upb_Message_New_inl(l, a); +} - if (!upb_Message_Next(msg, m, NULL, &f, &val, &iter)) { - jsonenc_err(e, "No value set in Value proto"); +void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l) { + void* mem = UPB_PTR_AT(msg, -sizeof(upb_Message_Internal), char); + memset(mem, 0, upb_msg_sizeof(l)); +} + +static bool realloc_internal(upb_Message* msg, size_t need, upb_Arena* arena) { + upb_Message_Internal* in = upb_Message_Getinternal(msg); + if (!in->internal) { + /* No internal data, allocate from scratch. */ + size_t size = UPB_MAX(128, _upb_Log2CeilingSize(need + overhead)); + upb_Message_InternalData* internal = upb_Arena_Malloc(arena, size); + if (!internal) return false; + internal->size = size; + internal->unknown_end = overhead; + internal->ext_begin = size; + in->internal = internal; + } else if (in->internal->ext_begin - in->internal->unknown_end < need) { + /* Internal data is too small, reallocate. */ + size_t new_size = _upb_Log2CeilingSize(in->internal->size + need); + size_t ext_bytes = in->internal->size - in->internal->ext_begin; + size_t new_ext_begin = new_size - ext_bytes; + upb_Message_InternalData* internal = + upb_Arena_Realloc(arena, in->internal, in->internal->size, new_size); + if (!internal) return false; + if (ext_bytes) { + /* Need to move extension data to the end. */ + char* ptr = (char*)internal; + memmove(ptr + new_ext_begin, ptr + internal->ext_begin, ext_bytes); + } + internal->ext_begin = new_ext_begin; + internal->size = new_size; + in->internal = internal; } + UPB_ASSERT(in->internal->ext_begin - in->internal->unknown_end >= need); + return true; +} - switch (upb_FieldDef_Number(f)) { - case 1: - jsonenc_putstr(e, "null"); - break; - case 2: - upb_JsonEncode_Double(e, val.double_val); - break; - case 3: - jsonenc_string(e, val.str_val); - break; - case 4: - jsonenc_putstr(e, val.bool_val ? "true" : "false"); - break; - case 5: - jsonenc_struct(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); - break; - case 6: - jsonenc_listvalue(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); - break; +bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, + upb_Arena* arena) { + if (!realloc_internal(msg, len, arena)) return false; + upb_Message_Internal* in = upb_Message_Getinternal(msg); + memcpy(UPB_PTR_AT(in->internal, in->internal->unknown_end, char), data, len); + in->internal->unknown_end += len; + return true; +} + +void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) { + upb_Message_Internal* in = upb_Message_Getinternal(msg); + if (in->internal) { + in->internal->unknown_end = overhead; } } -static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - switch (upb_MessageDef_WellKnownType(m)) { - case kUpb_WellKnown_Unspecified: - jsonenc_msg(e, msg, m); - break; - case kUpb_WellKnown_Any: - jsonenc_any(e, msg, m); - break; - case kUpb_WellKnown_FieldMask: - jsonenc_fieldmask(e, msg, m); - break; - case kUpb_WellKnown_Duration: - jsonenc_duration(e, msg, m); - break; - case kUpb_WellKnown_Timestamp: - jsonenc_timestamp(e, msg, m); - break; - case kUpb_WellKnown_DoubleValue: - case kUpb_WellKnown_FloatValue: - case kUpb_WellKnown_Int64Value: - case kUpb_WellKnown_UInt64Value: - case kUpb_WellKnown_Int32Value: - case kUpb_WellKnown_UInt32Value: - case kUpb_WellKnown_StringValue: - case kUpb_WellKnown_BytesValue: - case kUpb_WellKnown_BoolValue: - jsonenc_wrapper(e, msg, m); - break; - case kUpb_WellKnown_Value: - jsonenc_value(e, msg, m); - break; - case kUpb_WellKnown_ListValue: - jsonenc_listvalue(e, msg, m); - break; - case kUpb_WellKnown_Struct: - jsonenc_struct(e, msg, m); - break; +const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len) { + const upb_Message_Internal* in = upb_Message_Getinternal_const(msg); + if (in->internal) { + *len = in->internal->unknown_end - overhead; + return (char*)(in->internal + 1); + } else { + *len = 0; + return NULL; } } -static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, - const upb_FieldDef* f) { - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Bool: - jsonenc_putstr(e, val.bool_val ? "true" : "false"); - break; - case kUpb_CType_Float: - upb_JsonEncode_Float(e, val.float_val); - break; - case kUpb_CType_Double: - upb_JsonEncode_Double(e, val.double_val); - break; - case kUpb_CType_Int32: - jsonenc_printf(e, "%" PRId32, val.int32_val); - break; - case kUpb_CType_UInt32: - jsonenc_printf(e, "%" PRIu32, val.uint32_val); - break; - case kUpb_CType_Int64: - jsonenc_printf(e, "\"%" PRId64 "\"", val.int64_val); - break; - case kUpb_CType_UInt64: - jsonenc_printf(e, "\"%" PRIu64 "\"", val.uint64_val); - break; - case kUpb_CType_String: - jsonenc_string(e, val.str_val); - break; - case kUpb_CType_Bytes: - jsonenc_bytes(e, val.str_val); - break; - case kUpb_CType_Enum: - jsonenc_enum(val.int32_val, f, e); - break; - case kUpb_CType_Message: - jsonenc_msgfield(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); - break; +const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg, + size_t* count) { + const upb_Message_Internal* in = upb_Message_Getinternal_const(msg); + if (in->internal) { + *count = (in->internal->size - in->internal->ext_begin) / + sizeof(upb_Message_Extension); + return UPB_PTR_AT(in->internal, in->internal->ext_begin, void); + } else { + *count = 0; + return NULL; } } -static void jsonenc_mapkey(jsonenc* e, upb_MessageValue val, - const upb_FieldDef* f) { - jsonenc_putstr(e, "\""); +const upb_Message_Extension* _upb_Message_Getext( + const upb_Message* msg, const upb_MiniTable_Extension* e) { + size_t n; + const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &n); - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Bool: - jsonenc_putstr(e, val.bool_val ? "true" : "false"); - break; - case kUpb_CType_Int32: - jsonenc_printf(e, "%" PRId32, val.int32_val); - break; - case kUpb_CType_UInt32: - jsonenc_printf(e, "%" PRIu32, val.uint32_val); - break; - case kUpb_CType_Int64: - jsonenc_printf(e, "%" PRId64, val.int64_val); - break; - case kUpb_CType_UInt64: - jsonenc_printf(e, "%" PRIu64, val.uint64_val); - break; - case kUpb_CType_String: - jsonenc_stringbody(e, val.str_val); - break; - default: - UPB_UNREACHABLE(); + /* For now we use linear search exclusively to find extensions. If this + * becomes an issue due to messages with lots of extensions, we can introduce + * a table of some sort. */ + for (size_t i = 0; i < n; i++) { + if (ext[i].ext == e) { + return &ext[i]; + } } - jsonenc_putstr(e, "\":"); + return NULL; } -static void jsonenc_array(jsonenc* e, const upb_Array* arr, - const upb_FieldDef* f) { - size_t i; - size_t size = arr ? upb_Array_Size(arr) : 0; - bool first = true; - - jsonenc_putstr(e, "["); - - for (i = 0; i < size; i++) { - jsonenc_putsep(e, ",", &first); - jsonenc_scalar(e, upb_Array_Get(arr, i), f); +void _upb_Message_Clearext(upb_Message* msg, + const upb_MiniTable_Extension* ext_l) { + upb_Message_Internal* in = upb_Message_Getinternal(msg); + if (!in->internal) return; + const upb_Message_Extension* base = + UPB_PTR_AT(in->internal, in->internal->ext_begin, void); + upb_Message_Extension* ext = + (upb_Message_Extension*)_upb_Message_Getext(msg, ext_l); + if (ext) { + *ext = *base; + in->internal->ext_begin += sizeof(upb_Message_Extension); } +} - jsonenc_putstr(e, "]"); +upb_Message_Extension* _upb_Message_GetOrCreateExtension( + upb_Message* msg, const upb_MiniTable_Extension* e, upb_Arena* arena) { + upb_Message_Extension* ext = + (upb_Message_Extension*)_upb_Message_Getext(msg, e); + if (ext) return ext; + if (!realloc_internal(msg, sizeof(upb_Message_Extension), arena)) return NULL; + upb_Message_Internal* in = upb_Message_Getinternal(msg); + in->internal->ext_begin -= sizeof(upb_Message_Extension); + ext = UPB_PTR_AT(in->internal, in->internal->ext_begin, void); + memset(ext, 0, sizeof(upb_Message_Extension)); + ext->ext = e; + return ext; } -static void jsonenc_map(jsonenc* e, const upb_Map* map, const upb_FieldDef* f) { - const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); - const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); - const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); - size_t iter = kUpb_Map_Begin; - bool first = true; +size_t upb_Message_ExtensionCount(const upb_Message* msg) { + size_t count; + _upb_Message_Getexts(msg, &count); + return count; +} - jsonenc_putstr(e, "{"); +/** upb_Map *******************************************************************/ - if (map) { - while (upb_MapIterator_Next(map, &iter)) { - jsonenc_putsep(e, ",", &first); - jsonenc_mapkey(e, upb_MapIterator_Key(map, iter), key_f); - jsonenc_scalar(e, upb_MapIterator_Value(map, iter), val_f); - } +upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size) { + upb_Map* map = upb_Arena_Malloc(a, sizeof(upb_Map)); + + if (!map) { + return NULL; } - jsonenc_putstr(e, "}"); + upb_strtable_init(&map->table, 4, a); + map->key_size = key_size; + map->val_size = value_size; + + return map; } -static void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f, - upb_MessageValue val, bool* first) { - const char* name; +const float kUpb_FltInfinity = INFINITY; +const double kUpb_Infinity = INFINITY; - jsonenc_putsep(e, ",", first); - if (upb_FieldDef_IsExtension(f)) { - // TODO: For MessageSet, I would have expected this to print the message - // name here, but Python doesn't appear to do this. We should do more - // research here about what various implementations do. - jsonenc_printf(e, "\"[%s]\":", upb_FieldDef_FullName(f)); - } else { - if (e->options & upb_JsonEncode_UseProtoNames) { - name = upb_FieldDef_Name(f); - } else { - name = upb_FieldDef_JsonName(f); - } - jsonenc_printf(e, "\"%s\":", name); - } +#include +#include +#include +#include +#include +#include - if (upb_FieldDef_IsMap(f)) { - jsonenc_map(e, val.map_val, f); - } else if (upb_FieldDef_IsRepeated(f)) { - jsonenc_array(e, val.array_val, f); - } else { - jsonenc_scalar(e, val, f); - } +// Must be last. + +void upb_Status_Clear(upb_Status* status) { + if (!status) return; + status->ok = true; + status->msg[0] = '\0'; } -static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m, bool first) { - upb_MessageValue val; - const upb_FieldDef* f; +bool upb_Status_IsOk(const upb_Status* status) { return status->ok; } - if (e->options & upb_JsonEncode_EmitDefaults) { - /* Iterate over all fields. */ - int i = 0; - int n = upb_MessageDef_FieldCount(m); - for (i = 0; i < n; i++) { - f = upb_MessageDef_Field(m, i); - if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) { - jsonenc_fieldval(e, f, upb_Message_Get(msg, f), &first); - } - } - } else { - /* Iterate over non-empty fields. */ - size_t iter = kUpb_Message_Begin; - while (upb_Message_Next(msg, m, e->ext_pool, &f, &val, &iter)) { - jsonenc_fieldval(e, f, val, &first); - } - } +const char* upb_Status_ErrorMessage(const upb_Status* status) { + return status->msg; } -static void jsonenc_msg(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - jsonenc_putstr(e, "{"); - jsonenc_msgfields(e, msg, m, true); - jsonenc_putstr(e, "}"); +void upb_Status_SetErrorMessage(upb_Status* status, const char* msg) { + if (!status) return; + status->ok = false; + strncpy(status->msg, msg, _kUpb_Status_MaxMessage - 1); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; } -static size_t jsonenc_nullz(jsonenc* e, size_t size) { - size_t ret = e->ptr - e->buf + e->overflow; +void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + upb_Status_VSetErrorFormat(status, fmt, args); + va_end(args); +} - if (size > 0) { - if (e->ptr == e->end) e->ptr--; - *e->ptr = '\0'; - } +void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, + va_list args) { + if (!status) return; + status->ok = false; + vsnprintf(status->msg, sizeof(status->msg), fmt, args); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; +} - return ret; +void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, + va_list args) { + size_t len; + if (!status) return; + status->ok = false; + len = strlen(status->msg); + vsnprintf(status->msg + len, sizeof(status->msg) - len, fmt, args); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; } -size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, - const upb_DefPool* ext_pool, int options, char* buf, - size_t size, upb_Status* status) { - jsonenc e; +#include +#include +#include - e.buf = buf; - e.ptr = buf; - e.end = UPB_PTRADD(buf, size); - e.overflow = 0; - e.options = options; - e.ext_pool = ext_pool; - e.status = status; - e.arena = NULL; - if (setjmp(e.err)) return -1; +// Must be last. - jsonenc_msgfield(&e, msg, m); - if (e.arena) upb_Arena_Free(e.arena); - return jsonenc_nullz(&e, size); +/* Miscellaneous utilities ****************************************************/ + +static void upb_FixLocale(char* p) { + /* printf() is dependent on locales; sadly there is no easy and portable way + * to avoid this. This little post-processing step will translate 1,2 -> 1.2 + * since JSON needs the latter. Arguably a hack, but it is simple and the + * alternatives are far more complicated, platform-dependent, and/or larger + * in code size. */ + for (; *p; p++) { + if (*p == ',') *p = '.'; + } +} + +void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size) { + assert(size >= kUpb_RoundTripBufferSize); + snprintf(buf, size, "%.*g", DBL_DIG, val); + if (strtod(buf, NULL) != val) { + snprintf(buf, size, "%.*g", DBL_DIG + 2, val); + assert(strtod(buf, NULL) == val); + } + upb_FixLocale(buf); +} + +void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size) { + assert(size >= kUpb_RoundTripBufferSize); + snprintf(buf, size, "%.*g", FLT_DIG, val); + if (strtof(buf, NULL) != val) { + snprintf(buf, size, "%.*g", FLT_DIG + 3, val); + assert(strtof(buf, NULL) == val); + } + upb_FixLocale(buf); } -/** upb/port_undef.inc ************************************************************/ /* See port_def.inc. This should #undef all macros #defined there. */ #undef UPB_SIZE @@ -11090,6 +12640,7 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #undef UPB_ALIGN_DOWN #undef UPB_ALIGN_MALLOC #undef UPB_ALIGN_OF +#undef UPB_MALLOC_ALIGN #undef UPB_LIKELY #undef UPB_UNLIKELY #undef UPB_FORCEINLINE @@ -11113,3 +12664,5 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #undef UPB_UNPOISON_MEMORY_REGION #undef UPB_ASAN #undef UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 +#undef UPB_DEPRECATED +#undef UPB_GNUC_MIN diff --git a/ruby/ext/google/protobuf_c/ruby-upb.h b/ruby/ext/google/protobuf_c/ruby-upb.h index e57eb0edad..bb71990a92 100755 --- a/ruby/ext/google/protobuf_c/ruby-upb.h +++ b/ruby/ext/google/protobuf_c/ruby-upb.h @@ -1,32 +1,6 @@ // Ruby is still using proto3 enum semantics for proto2 #define UPB_DISABLE_PROTO2_ENUM_CHECKING /* Amalgamated source file */ -/* - * Copyright (c) 2009-2021, Google LLC - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Google LLC nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ /* * This is where we define macros used across upb. @@ -57,8 +31,20 @@ #error upb requires C99 or C++11 or MSVC >= 2015. #endif -#include +// Portable check for GCC minimum version: +// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +#define UPB_GNUC_MIN(x, y) \ + (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y)) +#else +#define UPB_GNUC_MIN(x, y) 0 +#endif + +#include +#include +#include #include +#include #if UINTPTR_MAX == 0xffffffff #define UPB_SIZE(size32, size64) size32 @@ -91,9 +77,10 @@ #define UPB_INLINE static #endif +#define UPB_MALLOC_ALIGN 8 #define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align)) #define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align)) -#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, 16) +#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, UPB_MALLOC_ALIGN) #define UPB_ALIGN_OF(type) offsetof (struct { char c; type member; }, member) /* Hints to the compiler about likely/unlikely branches. */ @@ -231,7 +218,11 @@ #undef UPB_FASTTABLE_SUPPORTED -/* ASAN poisoning (for arena) *************************************************/ +/* ASAN poisoning (for arena). + * If using UPB from an interpreted language like Ruby, a build of the + * interpreter compiled with ASAN enabled must be used in order to get sane and + * expected behavior. + */ #if defined(__SANITIZE_ADDRESS__) #define UPB_ASAN 1 @@ -263,16 +254,35 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); #define UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 0 #endif -/** upb/decode.h ************************************************************/ -/* - * upb_decode: parsing into a upb_Message using a upb_MiniTable. - */ +#if defined(__cplusplus) +#if defined(__clang__) || UPB_GNUC_MIN(6, 0) +// https://gcc.gnu.org/gcc-6/changes.html +#if __cplusplus >= 201402L +#define UPB_DEPRECATED [[deprecated]] +#else +#define UPB_DEPRECATED __attribute__((deprecated)) +#endif +#else +#define UPB_DEPRECATED +#endif +#else +#define UPB_DEPRECATED +#endif -#ifndef UPB_DECODE_H_ -#define UPB_DECODE_H_ +#ifndef UPB_INTERNAL_ARRAY_H_ +#define UPB_INTERNAL_ARRAY_H_ + +#include + + +#ifndef UPB_ARRAY_H_ +#define UPB_ARRAY_H_ + + +#ifndef UPB_MESSAGE_VALUE_H_ +#define UPB_MESSAGE_VALUE_H_ -/** upb/msg.h ************************************************************/ /* * Public APIs for message operations that do not require descriptors. * These functions can be used even in build that does not want to depend on @@ -284,97 +294,37 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); #ifndef UPB_MSG_H_ #define UPB_MSG_H_ -#include +#ifndef UPB_ARENA_H_ +#define UPB_ARENA_H_ -/** upb/upb.h ************************************************************/ -/* - * This file contains shared definitions that are widely used across upb. - */ +#include -#ifndef UPB_H_ -#define UPB_H_ -#include -#include -#include -#include -#include -#include +#ifndef UPB_ALLOC_H_ +#define UPB_ALLOC_H_ +// Must be last. #ifdef __cplusplus extern "C" { #endif -/* upb_Status *****************************************************************/ - -#define _kUpb_Status_MaxMessage 127 - -typedef struct { - bool ok; - char msg[_kUpb_Status_MaxMessage]; /* Error message; NULL-terminated. */ -} upb_Status; - -const char* upb_Status_ErrorMessage(const upb_Status* status); -bool upb_Status_IsOk(const upb_Status* status); - -/* These are no-op if |status| is NULL. */ -void upb_Status_Clear(upb_Status* status); -void upb_Status_SetErrorMessage(upb_Status* status, const char* msg); -void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) - UPB_PRINTF(2, 3); -void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, - va_list args) UPB_PRINTF(2, 0); -void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, - va_list args) UPB_PRINTF(2, 0); - -/** upb_StringView ************************************************************/ - -typedef struct { - const char* data; - size_t size; -} upb_StringView; - -UPB_INLINE upb_StringView upb_StringView_FromDataAndSize(const char* data, - size_t size) { - upb_StringView ret; - ret.data = data; - ret.size = size; - return ret; -} - -UPB_INLINE upb_StringView upb_StringView_FromString(const char* data) { - return upb_StringView_FromDataAndSize(data, strlen(data)); -} - -UPB_INLINE bool upb_StringView_IsEqual(upb_StringView a, upb_StringView b) { - return a.size == b.size && memcmp(a.data, b.data, a.size) == 0; -} - -#define UPB_STRINGVIEW_INIT(ptr, len) \ - { ptr, len } - -#define UPB_STRINGVIEW_FORMAT "%.*s" -#define UPB_STRINGVIEW_ARGS(view) (int)(view).size, (view).data - -/** upb_alloc *****************************************************************/ - -/* A upb_alloc is a possibly-stateful allocator object. - * - * It could either be an arena allocator (which doesn't require individual - * free() calls) or a regular malloc() (which does). The client must therefore - * free memory unless it knows that the allocator is an arena allocator. */ - -struct upb_alloc; typedef struct upb_alloc upb_alloc; -/* A malloc()/free() function. - * If "size" is 0 then the function acts like free(), otherwise it acts like - * realloc(). Only "oldsize" bytes from a previous allocation are preserved. */ +/* A combined `malloc()`/`free()` function. + * If `size` is 0 then the function acts like `free()`, otherwise it acts like + * `realloc()`. Only `oldsize` bytes from a previous allocation are + * preserved. */ typedef void* upb_alloc_func(upb_alloc* alloc, void* ptr, size_t oldsize, size_t size); +/* A upb_alloc is a possibly-stateful allocator object. + * + * It could either be an arena allocator (which doesn't require individual + * `free()` calls) or a regular `malloc()` (which does). The client must + * therefore free memory unless it knows that the allocator is an arena + * allocator. */ struct upb_alloc { upb_alloc_func* func; }; @@ -391,7 +341,7 @@ UPB_INLINE void* upb_realloc(upb_alloc* alloc, void* ptr, size_t oldsize, } UPB_INLINE void upb_free(upb_alloc* alloc, void* ptr) { - assert(alloc); + UPB_ASSERT(alloc); alloc->func(alloc, ptr, 0, 0); } @@ -414,7 +364,18 @@ UPB_INLINE void* upb_grealloc(void* ptr, size_t oldsize, size_t size) { UPB_INLINE void upb_gfree(void* ptr) { upb_free(&upb_alloc_global, ptr); } -/* upb_Arena ******************************************************************/ +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_ALLOC_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif /* upb_Arena is a specific allocator implementation that uses arena allocation. * The user provides an allocator that will be used to allocate the underlying @@ -430,7 +391,6 @@ UPB_INLINE void upb_gfree(void* ptr) { upb_free(&upb_alloc_global, ptr); } typedef void upb_CleanupFunc(void* ud); -struct upb_Arena; typedef struct upb_Arena upb_Arena; typedef struct { @@ -450,6 +410,8 @@ void upb_Arena_Free(upb_Arena* a); bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func); bool upb_Arena_Fuse(upb_Arena* a, upb_Arena* b); void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size); +size_t upb_Arena_SpaceAllocated(upb_Arena* arena); +uint32_t upb_Arena_DebugRefCount(upb_Arena* arena); UPB_INLINE upb_alloc* upb_Arena_Alloc(upb_Arena* a) { return (upb_alloc*)a; } @@ -458,18 +420,14 @@ UPB_INLINE size_t _upb_ArenaHas(upb_Arena* a) { return (size_t)(h->end - h->ptr); } -UPB_INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) { +UPB_INLINE void* _upb_Arena_FastMalloc(upb_Arena* a, size_t size) { _upb_ArenaHead* h = (_upb_ArenaHead*)a; - void* ret; - size = UPB_ALIGN_MALLOC(size); - - if (UPB_UNLIKELY(_upb_ArenaHas(a) < size)) { - return _upb_Arena_SlowMalloc(a, size); - } + void* ret = h->ptr; + UPB_ASSERT(UPB_ALIGN_MALLOC((uintptr_t)ret) == (uintptr_t)ret); + UPB_ASSERT(UPB_ALIGN_MALLOC(size) == size); + UPB_UNPOISON_MEMORY_REGION(ret, size); - ret = h->ptr; h->ptr += size; - UPB_UNPOISON_MEMORY_REGION(ret, size); #if UPB_ASAN { @@ -485,6 +443,16 @@ UPB_INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) { return ret; } +UPB_INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) { + size = UPB_ALIGN_MALLOC(size); + + if (UPB_UNLIKELY(_upb_ArenaHas(a) < size)) { + return _upb_Arena_SlowMalloc(a, size); + } + + return _upb_Arena_FastMalloc(a, size); +} + // Shrinks the last alloc from arena. // REQUIRES: (ptr, oldsize) was the last malloc/realloc from this arena. // We could also add a upb_Arena_TryShrinkLast() which is simply a no-op if @@ -504,17 +472,22 @@ UPB_INLINE void* upb_Arena_Realloc(upb_Arena* a, void* ptr, size_t oldsize, _upb_ArenaHead* h = (_upb_ArenaHead*)a; oldsize = UPB_ALIGN_MALLOC(oldsize); size = UPB_ALIGN_MALLOC(size); - if (size <= oldsize) { - if ((char*)ptr + oldsize == h->ptr) { - upb_Arena_ShrinkLast(a, ptr, oldsize, size); + bool is_most_recent_alloc = (uintptr_t)ptr + oldsize == (uintptr_t)h->ptr; + + if (is_most_recent_alloc) { + ptrdiff_t diff = size - oldsize; + if ((ptrdiff_t)_upb_ArenaHas(a) >= diff) { + h->ptr += diff; + return ptr; } + } else if (size <= oldsize) { return ptr; } void* ret = upb_Arena_Malloc(a, size); if (ret && oldsize > 0) { - memcpy(ret, ptr, oldsize); + memcpy(ret, ptr, UPB_MIN(oldsize, size)); } return ret; @@ -524,121 +497,23 @@ UPB_INLINE upb_Arena* upb_Arena_New(void) { return upb_Arena_Init(NULL, 0, &upb_alloc_global); } -/* Constants ******************************************************************/ - -/* A list of types as they are encoded on-the-wire. */ -typedef enum { - kUpb_WireType_Varint = 0, - kUpb_WireType_64Bit = 1, - kUpb_WireType_Delimited = 2, - kUpb_WireType_StartGroup = 3, - kUpb_WireType_EndGroup = 4, - kUpb_WireType_32Bit = 5 -} upb_WireType; - -/* The types a field can have. Note that this list is not identical to the - * types defined in descriptor.proto, which gives INT32 and SINT32 separate - * types (we distinguish the two with the "integer encoding" enum below). */ -typedef enum { - kUpb_CType_Bool = 1, - kUpb_CType_Float = 2, - kUpb_CType_Int32 = 3, - kUpb_CType_UInt32 = 4, - kUpb_CType_Enum = 5, /* Enum values are int32. */ - kUpb_CType_Message = 6, - kUpb_CType_Double = 7, - kUpb_CType_Int64 = 8, - kUpb_CType_UInt64 = 9, - kUpb_CType_String = 10, - kUpb_CType_Bytes = 11 -} upb_CType; - -/* The repeated-ness of each field; this matches descriptor.proto. */ -typedef enum { - kUpb_Label_Optional = 1, - kUpb_Label_Required = 2, - kUpb_Label_Repeated = 3 -} upb_Label; - -/* Descriptor types, as defined in descriptor.proto. */ -typedef enum { - kUpb_FieldType_Double = 1, - kUpb_FieldType_Float = 2, - kUpb_FieldType_Int64 = 3, - kUpb_FieldType_UInt64 = 4, - kUpb_FieldType_Int32 = 5, - kUpb_FieldType_Fixed64 = 6, - kUpb_FieldType_Fixed32 = 7, - kUpb_FieldType_Bool = 8, - kUpb_FieldType_String = 9, - kUpb_FieldType_Group = 10, - kUpb_FieldType_Message = 11, - kUpb_FieldType_Bytes = 12, - kUpb_FieldType_UInt32 = 13, - kUpb_FieldType_Enum = 14, - kUpb_FieldType_SFixed32 = 15, - kUpb_FieldType_SFixed64 = 16, - kUpb_FieldType_SInt32 = 17, - kUpb_FieldType_SInt64 = 18 -} upb_FieldType; - -#define kUpb_Map_Begin ((size_t)-1) - -UPB_INLINE bool _upb_IsLittleEndian(void) { - int x = 1; - return *(char*)&x == 1; -} - -UPB_INLINE uint32_t _upb_BigEndian_Swap32(uint32_t val) { - if (_upb_IsLittleEndian()) { - return val; - } else { - return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | - ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24); - } -} - -UPB_INLINE uint64_t _upb_BigEndian_Swap64(uint64_t val) { - if (_upb_IsLittleEndian()) { - return val; - } else { - return ((uint64_t)_upb_BigEndian_Swap32(val) << 32) | - _upb_BigEndian_Swap32(val >> 32); - } -} - -UPB_INLINE int _upb_Log2Ceiling(int x) { - if (x <= 1) return 0; -#ifdef __GNUC__ - return 32 - __builtin_clz(x - 1); -#else - int lg2 = 0; - while (1 << lg2 < x) lg2++; - return lg2; -#endif -} - -UPB_INLINE int _upb_Log2CeilingSize(int x) { return 1 << _upb_Log2Ceiling(x); } - - #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_H_ */ + +#endif /* UPB_ARENA_H_ */ + +// Must be last. #ifdef __cplusplus extern "C" { #endif -/** upb_Message - * *******************************************************************/ - typedef void upb_Message; /* For users these are opaque. They can be obtained from * upb_MessageDef_MiniTable() but users cannot access any of the members. */ -struct upb_MiniTable; typedef struct upb_MiniTable upb_MiniTable; /* Adds unknown data (serialized protobuf data) to the given message. The data @@ -652,167 +527,78 @@ const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len); /* Returns the number of extensions present in this message. */ size_t upb_Message_ExtensionCount(const upb_Message* msg); -/** upb_ExtensionRegistry *****************************************************/ +#ifdef __cplusplus +} /* extern "C" */ +#endif -/* Extension registry: a dynamic data structure that stores a map of: - * (upb_MiniTable, number) -> extension info - * - * upb_decode() uses upb_ExtensionRegistry to look up extensions while parsing - * binary format. - * - * upb_ExtensionRegistry is part of the mini-table (msglayout) family of - * objects. Like all mini-table objects, it is suitable for reflection-less - * builds that do not want to expose names into the binary. - * - * Unlike most mini-table types, upb_ExtensionRegistry requires dynamic memory - * allocation and dynamic initialization: - * * If reflection is being used, then upb_DefPool will construct an appropriate - * upb_ExtensionRegistry automatically. - * * For a mini-table only build, the user must manually construct the - * upb_ExtensionRegistry and populate it with all of the extensions the user - * cares about. - * * A third alternative is to manually unpack relevant extensions after the - * main parse is complete, similar to how Any works. This is perhaps the - * nicest solution from the perspective of reducing dependencies, avoiding - * dynamic memory allocation, and avoiding the need to parse uninteresting - * extensions. The downsides are: - * (1) parse errors are not caught during the main parse - * (2) the CPU hit of parsing comes during access, which could cause an - * undesirable stutter in application performance. - * - * Users cannot directly get or put into this map. Users can only add the - * extensions from a generated module and pass the extension registry to the - * binary decoder. - * - * A upb_DefPool provides a upb_ExtensionRegistry, so any users who use - * reflection do not need to populate a upb_ExtensionRegistry directly. - */ - -struct upb_ExtensionRegistry; -typedef struct upb_ExtensionRegistry upb_ExtensionRegistry; -/* Creates a upb_ExtensionRegistry in the given arena. The arena must outlive - * any use of the extreg. */ -upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena); +#endif /* UPB_MSG_INT_H_ */ -#ifdef __cplusplus -} /* extern "C" */ -#endif +#ifndef UPB_STRING_VIEW_H_ +#define UPB_STRING_VIEW_H_ -#endif /* UPB_MSG_INT_H_ */ +#include -/* Must be last. */ +// Must be last. #ifdef __cplusplus extern "C" { #endif -enum { - /* If set, strings will alias the input buffer instead of copying into the - * arena. */ - kUpb_DecodeOption_AliasString = 1, +typedef struct { + const char* data; + size_t size; +} upb_StringView; - /* If set, the parse will return failure if any message is missing any - * required fields when the message data ends. The parse will still continue, - * and the failure will only be reported at the end. - * - * IMPORTANT CAVEATS: - * - * 1. This can throw a false positive failure if an incomplete message is seen - * on the wire but is later completed when the sub-message occurs again. - * For this reason, a second pass is required to verify a failure, to be - * truly robust. - * - * 2. This can return a false success if you are decoding into a message that - * already has some sub-message fields present. If the sub-message does - * not occur in the binary payload, we will never visit it and discover the - * incomplete sub-message. For this reason, this check is only useful for - * implemting ParseFromString() semantics. For MergeFromString(), a - * post-parse validation step will always be necessary. */ - kUpb_DecodeOption_CheckRequired = 2, -}; +UPB_INLINE upb_StringView upb_StringView_FromDataAndSize(const char* data, + size_t size) { + upb_StringView ret; + ret.data = data; + ret.size = size; + return ret; +} -#define UPB_DECODE_MAXDEPTH(depth) ((depth) << 16) +UPB_INLINE upb_StringView upb_StringView_FromString(const char* data) { + return upb_StringView_FromDataAndSize(data, strlen(data)); +} -typedef enum { - kUpb_DecodeStatus_Ok = 0, - kUpb_DecodeStatus_Malformed = 1, // Wire format was corrupt - kUpb_DecodeStatus_OutOfMemory = 2, // Arena alloc failed - kUpb_DecodeStatus_BadUtf8 = 3, // String field had bad UTF-8 - kUpb_DecodeStatus_MaxDepthExceeded = 4, // Exceeded UPB_DECODE_MAXDEPTH +UPB_INLINE bool upb_StringView_IsEqual(upb_StringView a, upb_StringView b) { + return a.size == b.size && memcmp(a.data, b.data, a.size) == 0; +} - // kUpb_DecodeOption_CheckRequired failed (see above), but the parse otherwise - // succeeded. - kUpb_DecodeStatus_MissingRequired = 5, -} upb_DecodeStatus; +#define UPB_STRINGVIEW_INIT(ptr, len) \ + { ptr, len } -upb_DecodeStatus upb_Decode(const char* buf, size_t size, upb_Message* msg, - const upb_MiniTable* l, - const upb_ExtensionRegistry* extreg, int options, - upb_Arena* arena); +#define UPB_STRINGVIEW_FORMAT "%.*s" +#define UPB_STRINGVIEW_ARGS(view) (int)(view).size, (view).data #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_DECODE_H_ */ +#endif /* UPB_STRING_VIEW_H_ */ -/** upb/decode_internal.h ************************************************************/ /* - * Internal implementation details of the decoder that are shared between - * decode.c and decode_fast.c. + * This file contains shared definitions that are widely used across upb. */ -#ifndef UPB_DECODE_INT_H_ -#define UPB_DECODE_INT_H_ - -#include - -#include "third_party/utf8_range/utf8_range.h" - -/** upb/msg_internal.h ************************************************************/ -/* -** Our memory representation for parsing tables and messages themselves. -** Functions in this file are used by generated code and possibly reflection. -** -** The definitions in this file are internal to upb. -**/ - -#ifndef UPB_MSG_INT_H_ -#define UPB_MSG_INT_H_ +#ifndef UPB_H_ +#define UPB_H_ +#include +#include +#include +#include #include -#include #include +// TODO(b/232091617): Remove these and fix everything that breaks as a result. -/** upb/table_internal.h ************************************************************/ -/* - * upb_table - * - * This header is INTERNAL-ONLY! Its interfaces are not public or stable! - * This file defines very fast int->upb_value (inttable) and string->upb_value - * (strtable) hash tables. - * - * The table uses chained scatter with Brent's variation (inspired by the Lua - * implementation of hash tables). The hash function for strings is Austin - * Appleby's "MurmurHash." - * - * The inttable uses uintptr_t as its key, which guarantees it can be used to - * store pointers or integers of at least 32 bits (upb isn't really useful on - * systems where sizeof(void*) < 4). - * - * The table must be homogeneous (all values of the same type). In debug - * mode, we check this on insert and lookup. - */ - -#ifndef UPB_TABLE_H_ -#define UPB_TABLE_H_ - -#include -#include +#ifndef UPB_STATUS_H_ +#define UPB_STATUS_H_ +#include // Must be last. @@ -820,1489 +606,1570 @@ upb_DecodeStatus upb_Decode(const char* buf, size_t size, upb_Message* msg, extern "C" { #endif -/* upb_value ******************************************************************/ +#define _kUpb_Status_MaxMessage 127 typedef struct { - uint64_t val; -} upb_value; - -/* Variant that works with a length-delimited rather than NULL-delimited string, - * as supported by strtable. */ -char* upb_strdup2(const char* s, size_t len, upb_Arena* a); + bool ok; + char msg[_kUpb_Status_MaxMessage]; /* Error message; NULL-terminated. */ +} upb_Status; -UPB_INLINE void _upb_value_setval(upb_value* v, uint64_t val) { v->val = val; } +const char* upb_Status_ErrorMessage(const upb_Status* status); +bool upb_Status_IsOk(const upb_Status* status); -/* For each value ctype, define the following set of functions: - * - * // Get/set an int32 from a upb_value. - * int32_t upb_value_getint32(upb_value val); - * void upb_value_setint32(upb_value *val, int32_t cval); - * - * // Construct a new upb_value from an int32. - * upb_value upb_value_int32(int32_t val); */ -#define FUNCS(name, membername, type_t, converter, proto_type) \ - UPB_INLINE void upb_value_set##name(upb_value* val, type_t cval) { \ - val->val = (converter)cval; \ - } \ - UPB_INLINE upb_value upb_value_##name(type_t val) { \ - upb_value ret; \ - upb_value_set##name(&ret, val); \ - return ret; \ - } \ - UPB_INLINE type_t upb_value_get##name(upb_value val) { \ - return (type_t)(converter)val.val; \ - } +/* These are no-op if |status| is NULL. */ +void upb_Status_Clear(upb_Status* status); +void upb_Status_SetErrorMessage(upb_Status* status, const char* msg); +void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) + UPB_PRINTF(2, 3); +void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, + va_list args) UPB_PRINTF(2, 0); +void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, + va_list args) UPB_PRINTF(2, 0); -FUNCS(int32, int32, int32_t, int32_t, UPB_CTYPE_INT32) -FUNCS(int64, int64, int64_t, int64_t, UPB_CTYPE_INT64) -FUNCS(uint32, uint32, uint32_t, uint32_t, UPB_CTYPE_UINT32) -FUNCS(uint64, uint64, uint64_t, uint64_t, UPB_CTYPE_UINT64) -FUNCS(bool, _bool, bool, bool, UPB_CTYPE_BOOL) -FUNCS(cstr, cstr, char*, uintptr_t, UPB_CTYPE_CSTR) -FUNCS(ptr, ptr, void*, uintptr_t, UPB_CTYPE_PTR) -FUNCS(constptr, constptr, const void*, uintptr_t, UPB_CTYPE_CONSTPTR) +#ifdef __cplusplus +} /* extern "C" */ +#endif -#undef FUNCS -UPB_INLINE void upb_value_setfloat(upb_value* val, float cval) { - memcpy(&val->val, &cval, sizeof(cval)); -} +#endif /* UPB_STATUS_H_ */ -UPB_INLINE void upb_value_setdouble(upb_value* val, double cval) { - memcpy(&val->val, &cval, sizeof(cval)); -} +// Must be last. -UPB_INLINE upb_value upb_value_float(float cval) { - upb_value ret; - upb_value_setfloat(&ret, cval); - return ret; -} +#ifdef __cplusplus +extern "C" { +#endif -UPB_INLINE upb_value upb_value_double(double cval) { - upb_value ret; - upb_value_setdouble(&ret, cval); - return ret; -} +// These types appear in circular references so we need to forward-declare them. +// There is no obviously good place for this so let's just put it here. +typedef struct upb_Array upb_Array; +typedef struct upb_Map upb_Map; -#undef SET_TYPE +/* Constants ******************************************************************/ -/* upb_tabkey *****************************************************************/ +/* A list of types as they are encoded on-the-wire. */ +typedef enum { + kUpb_WireType_Varint = 0, + kUpb_WireType_64Bit = 1, + kUpb_WireType_Delimited = 2, + kUpb_WireType_StartGroup = 3, + kUpb_WireType_EndGroup = 4, + kUpb_WireType_32Bit = 5 +} upb_WireType; -/* Either: - * 1. an actual integer key, or - * 2. a pointer to a string prefixed by its uint32_t length, owned by us. - * - * ...depending on whether this is a string table or an int table. We would - * make this a union of those two types, but C89 doesn't support statically - * initializing a non-first union member. */ -typedef uintptr_t upb_tabkey; +/* The types a field can have. Note that this list is not identical to the + * types defined in descriptor.proto, which gives INT32 and SINT32 separate + * types (we distinguish the two with the "integer encoding" enum below). */ +typedef enum { + kUpb_CType_Bool = 1, + kUpb_CType_Float = 2, + kUpb_CType_Int32 = 3, + kUpb_CType_UInt32 = 4, + kUpb_CType_Enum = 5, /* Enum values are int32. */ + kUpb_CType_Message = 6, + kUpb_CType_Double = 7, + kUpb_CType_Int64 = 8, + kUpb_CType_UInt64 = 9, + kUpb_CType_String = 10, + kUpb_CType_Bytes = 11 +} upb_CType; -UPB_INLINE char* upb_tabstr(upb_tabkey key, uint32_t* len) { - char* mem = (char*)key; - if (len) memcpy(len, mem, sizeof(*len)); - return mem + sizeof(*len); -} +/* The repeated-ness of each field; this matches descriptor.proto. */ +typedef enum { + kUpb_Label_Optional = 1, + kUpb_Label_Required = 2, + kUpb_Label_Repeated = 3 +} upb_Label; -UPB_INLINE upb_StringView upb_tabstrview(upb_tabkey key) { - upb_StringView ret; - uint32_t len; - ret.data = upb_tabstr(key, &len); - ret.size = len; - return ret; +/* Descriptor types, as defined in descriptor.proto. */ +typedef enum { + kUpb_FieldType_Double = 1, + kUpb_FieldType_Float = 2, + kUpb_FieldType_Int64 = 3, + kUpb_FieldType_UInt64 = 4, + kUpb_FieldType_Int32 = 5, + kUpb_FieldType_Fixed64 = 6, + kUpb_FieldType_Fixed32 = 7, + kUpb_FieldType_Bool = 8, + kUpb_FieldType_String = 9, + kUpb_FieldType_Group = 10, + kUpb_FieldType_Message = 11, + kUpb_FieldType_Bytes = 12, + kUpb_FieldType_UInt32 = 13, + kUpb_FieldType_Enum = 14, + kUpb_FieldType_SFixed32 = 15, + kUpb_FieldType_SFixed64 = 16, + kUpb_FieldType_SInt32 = 17, + kUpb_FieldType_SInt64 = 18, +} upb_FieldType; + +#define kUpb_FieldType_SizeOf 19 + +#define kUpb_Map_Begin ((size_t)-1) + +UPB_INLINE bool _upb_IsLittleEndian(void) { + int x = 1; + return *(char*)&x == 1; } -/* upb_tabval *****************************************************************/ +UPB_INLINE uint32_t _upb_BigEndian_Swap32(uint32_t val) { + if (_upb_IsLittleEndian()) { + return val; + } else { + return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | + ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24); + } +} -typedef struct upb_tabval { - uint64_t val; -} upb_tabval; +UPB_INLINE uint64_t _upb_BigEndian_Swap64(uint64_t val) { + if (_upb_IsLittleEndian()) { + return val; + } else { + return ((uint64_t)_upb_BigEndian_Swap32((uint32_t)val) << 32) | + _upb_BigEndian_Swap32((uint32_t)(val >> 32)); + } +} -#define UPB_TABVALUE_EMPTY_INIT \ - { -1 } +UPB_INLINE int _upb_Log2Ceiling(int x) { + if (x <= 1) return 0; +#ifdef __GNUC__ + return 32 - __builtin_clz(x - 1); +#else + int lg2 = 0; + while (1 << lg2 < x) lg2++; + return lg2; +#endif +} -/* upb_table ******************************************************************/ +UPB_INLINE int _upb_Log2CeilingSize(int x) { return 1 << _upb_Log2Ceiling(x); } -typedef struct _upb_tabent { - upb_tabkey key; - upb_tabval val; +#ifdef __cplusplus +} /* extern "C" */ +#endif - /* Internal chaining. This is const so we can create static initializers for - * tables. We cast away const sometimes, but *only* when the containing - * upb_table is known to be non-const. This requires a bit of care, but - * the subtlety is confined to table.c. */ - const struct _upb_tabent* next; -} upb_tabent; -typedef struct { - size_t count; /* Number of entries in the hash part. */ - uint32_t mask; /* Mask to turn hash value -> bucket. */ - uint32_t max_count; /* Max count before we hit our load limit. */ - uint8_t size_lg2; /* Size of the hashtable part is 2^size_lg2 entries. */ - upb_tabent* entries; -} upb_table; +#endif /* UPB_H_ */ -typedef struct { - upb_table t; -} upb_strtable; +// Must be last. -typedef struct { - upb_table t; /* For entries that don't fit in the array part. */ - const upb_tabval* array; /* Array part of the table. See const note above. */ - size_t array_size; /* Array part size. */ - size_t array_count; /* Array part number of elements. */ -} upb_inttable; +#ifdef __cplusplus +extern "C" { +#endif -UPB_INLINE size_t upb_table_size(const upb_table* t) { - if (t->size_lg2 == 0) - return 0; - else - return 1 << t->size_lg2; -} +// Definitions common to both upb_Array and upb_Map. -/* Internal-only functions, in .h file only out of necessity. */ -UPB_INLINE bool upb_tabent_isempty(const upb_tabent* e) { return e->key == 0; } +typedef union { + bool bool_val; + float float_val; + double double_val; + int32_t int32_val; + int64_t int64_val; + uint32_t uint32_val; + uint64_t uint64_val; + const upb_Array* array_val; + const upb_Map* map_val; + const upb_Message* msg_val; + upb_StringView str_val; +} upb_MessageValue; -/* Initialize and uninitialize a table, respectively. If memory allocation - * failed, false is returned that the table is uninitialized. */ -bool upb_inttable_init(upb_inttable* table, upb_Arena* a); -bool upb_strtable_init(upb_strtable* table, size_t expected_size, upb_Arena* a); +typedef union { + upb_Array* array; + upb_Map* map; + upb_Message* msg; +} upb_MutableMessageValue; -/* Returns the number of values in the table. */ -size_t upb_inttable_count(const upb_inttable* t); -UPB_INLINE size_t upb_strtable_count(const upb_strtable* t) { - return t->t.count; -} +#ifdef __cplusplus +} /* extern "C" */ +#endif -void upb_strtable_clear(upb_strtable* t); -/* Inserts the given key into the hashtable with the given value. The key must - * not already exist in the hash table. For string tables, the key must be - * NULL-terminated, and the table will make an internal copy of the key. - * Inttables must not insert a value of UINTPTR_MAX. - * - * If a table resize was required but memory allocation failed, false is - * returned and the table is unchanged. */ -bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, - upb_Arena* a); -bool upb_strtable_insert(upb_strtable* t, const char* key, size_t len, - upb_value val, upb_Arena* a); +#endif /* UPB_MESSAGE_VALUE_H_ */ -/* Looks up key in this table, returning "true" if the key was found. - * If v is non-NULL, copies the value for this key into *v. */ -bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v); -bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, - upb_value* v); +// Must be last. -/* For NULL-terminated strings. */ -UPB_INLINE bool upb_strtable_lookup(const upb_strtable* t, const char* key, - upb_value* v) { - return upb_strtable_lookup2(t, key, strlen(key), v); -} +#ifdef __cplusplus +extern "C" { +#endif -/* Removes an item from the table. Returns true if the remove was successful, - * and stores the removed item in *val if non-NULL. */ -bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val); -bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, - upb_value* val); +/* Creates a new array on the given arena that holds elements of this type. */ +upb_Array* upb_Array_New(upb_Arena* a, upb_CType type); -UPB_INLINE bool upb_strtable_remove(upb_strtable* t, const char* key, - upb_value* v) { - return upb_strtable_remove2(t, key, strlen(key), v); -} +/* Returns the number of elements in the array. */ +size_t upb_Array_Size(const upb_Array* arr); -/* Updates an existing entry in an inttable. If the entry does not exist, - * returns false and does nothing. Unlike insert/remove, this does not - * invalidate iterators. */ -bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val); +/* Returns the given element, which must be within the array's current size. */ +upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i); -/* Optimizes the table for the current set of entries, for both memory use and - * lookup time. Client should call this after all entries have been inserted; - * inserting more entries is legal, but will likely require a table resize. */ -void upb_inttable_compact(upb_inttable* t, upb_Arena* a); +/* Sets the given element, which must be within the array's current size. */ +void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val); -/* Exposed for testing only. */ -bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a); +/* Appends an element to the array. Returns false on allocation failure. */ +bool upb_Array_Append(upb_Array* array, upb_MessageValue val, upb_Arena* arena); -/* Iterators ******************************************************************/ +/* Moves elements within the array using memmove(). Like memmove(), the source + * and destination elements may be overlapping. */ +void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx, + size_t count); -/* Iteration over inttable. - * - * intptr_t iter = UPB_INTTABLE_BEGIN; - * uintptr_t key; - * upb_value val; - * while (upb_inttable_next2(t, &key, &val, &iter)) { - * // ... - * } - */ +/* Inserts one or more empty elements into the array. Existing elements are + * shifted right. The new elements have undefined state and must be set with + * `upb_Array_Set()`. + * REQUIRES: `i <= upb_Array_Size(arr)` */ +bool upb_Array_Insert(upb_Array* array, size_t i, size_t count, + upb_Arena* arena); -#define UPB_INTTABLE_BEGIN -1 +/* Deletes one or more elements from the array. Existing elements are shifted + * left. + * REQUIRES: `i + count <= upb_Array_Size(arr)` */ +void upb_Array_Delete(upb_Array* array, size_t i, size_t count); -bool upb_inttable_next2(const upb_inttable* t, uintptr_t* key, upb_value* val, - intptr_t* iter); -void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter); +/* Changes the size of a vector. New elements are initialized to empty/0. + * Returns false on allocation failure. */ +bool upb_Array_Resize(upb_Array* array, size_t size, upb_Arena* arena); -/* Iteration over strtable. - * - * intptr_t iter = UPB_INTTABLE_BEGIN; - * upb_StringView key; - * upb_value val; - * while (upb_strtable_next2(t, &key, &val, &iter)) { - * // ... - * } - */ +#ifdef __cplusplus +} /* extern "C" */ +#endif -#define UPB_STRTABLE_BEGIN -1 -bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key, - upb_value* val, intptr_t* iter); -void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter); +#endif /* UPB_ARRAY_H_ */ -/* DEPRECATED iterators, slated for removal. - * - * Iterators for int and string tables. We are subject to some kind of unusual - * design constraints: - * - * For high-level languages: - * - we must be able to guarantee that we don't crash or corrupt memory even if - * the program accesses an invalidated iterator. - * - * For C++11 range-based for: - * - iterators must be copyable - * - iterators must be comparable - * - it must be possible to construct an "end" value. - * - * Iteration order is undefined. - * - * Modifying the table invalidates iterators. upb_{str,int}table_done() is - * guaranteed to work even on an invalidated iterator, as long as the table it - * is iterating over has not been freed. Calling next() or accessing data from - * an invalidated iterator yields unspecified elements from the table, but it is - * guaranteed not to crash and to return real table elements (except when done() - * is true). */ +// Must be last. -/* upb_strtable_iter **********************************************************/ +#ifdef __cplusplus +extern "C" { +#endif -/* upb_strtable_iter i; - * upb_strtable_begin(&i, t); - * for(; !upb_strtable_done(&i); upb_strtable_next(&i)) { - * const char *key = upb_strtable_iter_key(&i); - * const upb_value val = upb_strtable_iter_value(&i); - * // ... - * } - */ +/* Our internal representation for repeated fields. */ +struct upb_Array { + uintptr_t data; /* Tagged ptr: low 3 bits of ptr are lg2(elem size). */ + size_t size; /* The number of elements in the array. */ + size_t capacity; /* Allocated storage. Measured in elements. */ +}; -typedef struct { - const upb_strtable* t; - size_t index; -} upb_strtable_iter; +UPB_INLINE const void* _upb_array_constptr(const upb_Array* arr) { + UPB_ASSERT((arr->data & 7) <= 4); + return (void*)(arr->data & ~(uintptr_t)7); +} -void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t); -void upb_strtable_next(upb_strtable_iter* i); -bool upb_strtable_done(const upb_strtable_iter* i); -upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i); -upb_value upb_strtable_iter_value(const upb_strtable_iter* i); -void upb_strtable_iter_setdone(upb_strtable_iter* i); -bool upb_strtable_iter_isequal(const upb_strtable_iter* i1, - const upb_strtable_iter* i2); +UPB_INLINE uintptr_t _upb_array_tagptr(void* ptr, int elem_size_lg2) { + UPB_ASSERT(elem_size_lg2 <= 4); + return (uintptr_t)ptr | elem_size_lg2; +} -/* upb_inttable_iter **********************************************************/ +UPB_INLINE void* _upb_array_ptr(upb_Array* arr) { + return (void*)_upb_array_constptr(arr); +} -/* upb_inttable_iter i; - * upb_inttable_begin(&i, t); - * for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { - * uintptr_t key = upb_inttable_iter_key(&i); - * upb_value val = upb_inttable_iter_value(&i); - * // ... - * } - */ +UPB_INLINE uintptr_t _upb_tag_arrptr(void* ptr, int elem_size_lg2) { + UPB_ASSERT(elem_size_lg2 <= 4); + UPB_ASSERT(((uintptr_t)ptr & 7) == 0); + return (uintptr_t)ptr | (unsigned)elem_size_lg2; +} -typedef struct { - const upb_inttable* t; - size_t index; - bool array_part; -} upb_inttable_iter; +UPB_INLINE upb_Array* _upb_Array_New(upb_Arena* a, size_t init_capacity, + int elem_size_lg2) { + const size_t arr_size = UPB_ALIGN_UP(sizeof(upb_Array), UPB_MALLOC_ALIGN); + const size_t bytes = arr_size + (init_capacity << elem_size_lg2); + upb_Array* arr = (upb_Array*)upb_Arena_Malloc(a, bytes); + if (!arr) return NULL; + arr->data = _upb_tag_arrptr(UPB_PTR_AT(arr, arr_size, void), elem_size_lg2); + arr->size = 0; + arr->capacity = init_capacity; + return arr; +} -UPB_INLINE const upb_tabent* str_tabent(const upb_strtable_iter* i) { - return &i->t->t.entries[i->index]; +/* Resizes the capacity of the array to be at least min_size. */ +bool _upb_array_realloc(upb_Array* arr, size_t min_size, upb_Arena* arena); + +/* Fallback functions for when the accessors require a resize. */ +void* _upb_Array_Resize_fallback(upb_Array** arr_ptr, size_t size, + int elem_size_lg2, upb_Arena* arena); +bool _upb_Array_Append_fallback(upb_Array** arr_ptr, const void* value, + int elem_size_lg2, upb_Arena* arena); + +UPB_INLINE bool _upb_array_reserve(upb_Array* arr, size_t size, + upb_Arena* arena) { + if (arr->capacity < size) return _upb_array_realloc(arr, size, arena); + return true; } -void upb_inttable_begin(upb_inttable_iter* i, const upb_inttable* t); -void upb_inttable_next(upb_inttable_iter* i); -bool upb_inttable_done(const upb_inttable_iter* i); -uintptr_t upb_inttable_iter_key(const upb_inttable_iter* i); -upb_value upb_inttable_iter_value(const upb_inttable_iter* i); -void upb_inttable_iter_setdone(upb_inttable_iter* i); -bool upb_inttable_iter_isequal(const upb_inttable_iter* i1, - const upb_inttable_iter* i2); +UPB_INLINE bool _upb_Array_Resize(upb_Array* arr, size_t size, + upb_Arena* arena) { + if (!_upb_array_reserve(arr, size, arena)) return false; + arr->size = size; + return true; +} -uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed); +UPB_INLINE void _upb_array_detach(const void* msg, size_t ofs) { + *UPB_PTR_AT(msg, ofs, upb_Array*) = NULL; +} + +UPB_INLINE const void* _upb_array_accessor(const void* msg, size_t ofs, + size_t* size) { + const upb_Array* arr = *UPB_PTR_AT(msg, ofs, const upb_Array*); + if (arr) { + if (size) *size = arr->size; + return _upb_array_constptr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE void* _upb_array_mutable_accessor(void* msg, size_t ofs, + size_t* size) { + upb_Array* arr = *UPB_PTR_AT(msg, ofs, upb_Array*); + if (arr) { + if (size) *size = arr->size; + return _upb_array_ptr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE void* _upb_Array_Resize_accessor2(void* msg, size_t ofs, size_t size, + int elem_size_lg2, + upb_Arena* arena) { + upb_Array** arr_ptr = UPB_PTR_AT(msg, ofs, upb_Array*); + upb_Array* arr = *arr_ptr; + if (!arr || arr->capacity < size) { + return _upb_Array_Resize_fallback(arr_ptr, size, elem_size_lg2, arena); + } + arr->size = size; + return _upb_array_ptr(arr); +} + +UPB_INLINE bool _upb_Array_Append_accessor2(void* msg, size_t ofs, + int elem_size_lg2, + const void* value, + upb_Arena* arena) { + upb_Array** arr_ptr = UPB_PTR_AT(msg, ofs, upb_Array*); + size_t elem_size = 1 << elem_size_lg2; + upb_Array* arr = *arr_ptr; + void* ptr; + if (!arr || arr->size == arr->capacity) { + return _upb_Array_Append_fallback(arr_ptr, value, elem_size_lg2, arena); + } + ptr = _upb_array_ptr(arr); + memcpy(UPB_PTR_AT(ptr, arr->size * elem_size, char), value, elem_size); + arr->size++; + return true; +} + +/* Used by old generated code, remove once all code has been regenerated. */ +UPB_INLINE int _upb_sizelg2(upb_CType type) { + switch (type) { + case kUpb_CType_Bool: + return 0; + case kUpb_CType_Float: + case kUpb_CType_Int32: + case kUpb_CType_UInt32: + case kUpb_CType_Enum: + return 2; + case kUpb_CType_Message: + return UPB_SIZE(2, 3); + case kUpb_CType_Double: + case kUpb_CType_Int64: + case kUpb_CType_UInt64: + return 3; + case kUpb_CType_String: + case kUpb_CType_Bytes: + return UPB_SIZE(3, 4); + } + UPB_UNREACHABLE(); +} + +UPB_INLINE void* _upb_Array_Resize_accessor(void* msg, size_t ofs, size_t size, + upb_CType type, upb_Arena* arena) { + return _upb_Array_Resize_accessor2(msg, ofs, size, _upb_sizelg2(type), arena); +} + +UPB_INLINE bool _upb_Array_Append_accessor(void* msg, size_t ofs, + size_t elem_size, upb_CType type, + const void* value, + upb_Arena* arena) { + (void)elem_size; + return _upb_Array_Append_accessor2(msg, ofs, _upb_sizelg2(type), value, + arena); +} #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_TABLE_H_ */ +#endif /* UPB_INTERNAL_ARRAY_H_ */ -/* Must be last. */ +#ifndef UPB_INTERNAL_ATOI_H_ +#define UPB_INTERNAL_ATOI_H_ + +// Must be last. #ifdef __cplusplus extern "C" { #endif -/** upb_*Int* conversion routines ********************************************/ - -UPB_INLINE int32_t _upb_Int32_FromI(int v) { return (int32_t)v; } +// We use these hand-written routines instead of strto[u]l() because the "long +// long" variants aren't in c89. Also our version allows setting a ptr limit. +// Return the new position of the pointer after parsing the int, or NULL on +// integer overflow. -UPB_INLINE int64_t _upb_Int64_FromLL(long long v) { return (int64_t)v; } +const char* upb_BufToUint64(const char* ptr, const char* end, uint64_t* val); +const char* upb_BufToInt64(const char* ptr, const char* end, int64_t* val, + bool* is_neg); -UPB_INLINE uint32_t _upb_UInt32_FromU(unsigned v) { return (uint32_t)v; } +#ifdef __cplusplus +} /* extern "C" */ +#endif -UPB_INLINE uint64_t _upb_UInt64_FromULL(unsigned long long v) { - return (uint64_t)v; -} -/** upb_MiniTable *************************************************************/ +#endif /* UPB_INTERNAL_ATOI_H_ */ -/* upb_MiniTable represents the memory layout of a given upb_MessageDef. The - * members are public so generated code can initialize them, but users MUST NOT - * read or write any of its members. */ +#ifndef UPB_MAP_H_ +#define UPB_MAP_H_ -typedef struct { - uint32_t number; - uint16_t offset; - int16_t presence; // If >0, hasbit_index. If <0, ~oneof_index - uint16_t submsg_index; // undefined if descriptortype != MESSAGE/GROUP/ENUM - uint8_t descriptortype; - uint8_t mode; /* upb_FieldMode | upb_LabelFlags | - (upb_FieldRep << kUpb_FieldRep_Shift) */ -} upb_MiniTable_Field; -typedef enum { - kUpb_FieldMode_Map = 0, - kUpb_FieldMode_Array = 1, - kUpb_FieldMode_Scalar = 2, +// Must be last. - kUpb_FieldMode_Mask = 3, /* Mask to isolate the mode from upb_FieldRep. */ -} upb_FieldMode; +#ifdef __cplusplus +extern "C" { +#endif -/* Extra flags on the mode field. */ -typedef enum { - kUpb_LabelFlags_IsPacked = 4, - kUpb_LabelFlags_IsExtension = 8, -} upb_LabelFlags; +/* Creates a new map on the given arena with the given key/value size. */ +upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type); -// Note: we sort by this number when calculating layout order. -typedef enum { - kUpb_FieldRep_1Byte = 0, - kUpb_FieldRep_4Byte = 1, - kUpb_FieldRep_StringView = 2, - kUpb_FieldRep_Pointer = 3, - kUpb_FieldRep_8Byte = 4, +/* Returns the number of entries in the map. */ +size_t upb_Map_Size(const upb_Map* map); - kUpb_FieldRep_Shift = 5, // Bit offset of the rep in upb_MiniTable_Field.mode - kUpb_FieldRep_Max = kUpb_FieldRep_8Byte, -} upb_FieldRep; +/* Stores a value for the given key into |*val| (or the zero value if the key is + * not present). Returns whether the key was present. The |val| pointer may be + * NULL, in which case the function tests whether the given key is present. */ +bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, + upb_MessageValue* val); -UPB_INLINE upb_FieldMode upb_FieldMode_Get(const upb_MiniTable_Field* field) { - return (upb_FieldMode)(field->mode & 3); -} +/* Removes all entries in the map. */ +void upb_Map_Clear(upb_Map* map); -UPB_INLINE bool upb_IsRepeatedOrMap(const upb_MiniTable_Field* field) { - /* This works because upb_FieldMode has no value 3. */ - return !(field->mode & kUpb_FieldMode_Scalar); +typedef enum { + // LINT.IfChange + kUpb_MapInsertStatus_Inserted = 0, + kUpb_MapInsertStatus_Replaced = 1, + kUpb_MapInsertStatus_OutOfMemory = 2, + // LINT.ThenChange(//depot/google3/third_party/upb/upb/msg_internal.h) +} upb_MapInsertStatus; + +/* Sets the given key to the given value, returning whether the key was inserted + * or replaced. If the key was inserted, then any existing iterators will be + * invalidated. */ +upb_MapInsertStatus upb_Map_Insert(upb_Map* map, upb_MessageValue key, + upb_MessageValue val, upb_Arena* arena); + +/* Sets the given key to the given value. Returns false if memory allocation + * failed. If the key is newly inserted, then any existing iterators will be + * invalidated. */ +UPB_INLINE bool upb_Map_Set(upb_Map* map, upb_MessageValue key, + upb_MessageValue val, upb_Arena* arena) { + return upb_Map_Insert(map, key, val, arena) != + kUpb_MapInsertStatus_OutOfMemory; } -UPB_INLINE bool upb_IsSubMessage(const upb_MiniTable_Field* field) { - return field->descriptortype == kUpb_FieldType_Message || - field->descriptortype == kUpb_FieldType_Group; -} +/* Deletes this key from the table. Returns true if the key was present. */ +bool upb_Map_Delete(upb_Map* map, upb_MessageValue key); -struct upb_Decoder; -struct upb_MiniTable; +/* Map iteration: + * + * size_t iter = kUpb_Map_Begin; + * while (upb_MapIterator_Next(map, &iter)) { + * upb_MessageValue key = upb_MapIterator_Key(map, iter); + * upb_MessageValue val = upb_MapIterator_Value(map, iter); + * + * // If mutating is desired. + * upb_MapIterator_SetValue(map, iter, value2); + * } + */ -typedef const char* _upb_FieldParser(struct upb_Decoder* d, const char* ptr, - upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t data); +/* Advances to the next entry. Returns false if no more entries are present. */ +bool upb_MapIterator_Next(const upb_Map* map, size_t* iter); -typedef struct { - uint64_t field_data; - _upb_FieldParser* field_parser; -} _upb_FastTable_Entry; +/* Returns true if the iterator still points to a valid entry, or false if the + * iterator is past the last element. It is an error to call this function with + * kUpb_Map_Begin (you must call next() at least once first). */ +bool upb_MapIterator_Done(const upb_Map* map, size_t iter); -typedef struct { - const int32_t* values; // List of values <0 or >63 - uint64_t mask; // Bits are set for acceptable value 0 <= x < 64 - int value_count; -} upb_MiniTable_Enum; +/* Returns the key and value for this entry of the map. */ +upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter); +upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter); -UPB_INLINE bool upb_MiniTable_Enum_CheckValue(const upb_MiniTable_Enum* e, - int32_t val) { - uint32_t uval = (uint32_t)val; - if (uval < 64) return e->mask & (1 << uval); - // OPT: binary search long lists? - int n = e->value_count; - for (int i = 0; i < n; i++) { - if (e->values[i] == val) return true; - } - return false; -} +/* Sets the value for this entry. The iterator must not be done, and the + * iterator must not have been initialized const. */ +void upb_MapIterator_SetValue(upb_Map* map, size_t iter, + upb_MessageValue value); -typedef union { - const struct upb_MiniTable* submsg; - const upb_MiniTable_Enum* subenum; -} upb_MiniTable_Sub; +#ifdef __cplusplus +} /* extern "C" */ +#endif -typedef enum { - kUpb_ExtMode_NonExtendable = 0, // Non-extendable message. - kUpb_ExtMode_Extendable = 1, // Normal extendable message. - kUpb_ExtMode_IsMessageSet = 2, // MessageSet message. - kUpb_ExtMode_IsMessageSet_ITEM = - 3, // MessageSet item (temporary only, see decode.c) - // During table building we steal a bit to indicate that the message is a map - // entry. *Only* used during table building! - kUpb_ExtMode_IsMapEntry = 4, -} upb_ExtMode; +#endif /* UPB_MAP_H_ */ -/* MessageSet wire format is: - * message MessageSet { - * repeated group Item = 1 { - * required int32 type_id = 2; - * required string message = 3; - * } - * } - */ -typedef enum { - _UPB_MSGSET_ITEM = 1, - _UPB_MSGSET_TYPEID = 2, - _UPB_MSGSET_MESSAGE = 3, -} upb_msgext_fieldnum; +/* +** Our memory representation for parsing tables and messages themselves. +** Functions in this file are used by generated code and possibly reflection. +** +** The definitions in this file are internal to upb. +**/ -struct upb_MiniTable { - const upb_MiniTable_Sub* subs; - const upb_MiniTable_Field* fields; - /* Must be aligned to sizeof(void*). Doesn't include internal members like - * unknown fields, extension dict, pointer to msglayout, etc. */ - uint16_t size; - uint16_t field_count; - uint8_t ext; // upb_ExtMode, declared as uint8_t so sizeof(ext) == 1 - uint8_t dense_below; - uint8_t table_mask; - uint8_t required_count; // Required fields have the lowest hasbits. - /* To statically initialize the tables of variable length, we need a flexible - * array member, and we need to compile in gnu99 mode (constant initialization - * of flexible array members is a GNU extension, not in C99 unfortunately. */ - _upb_FastTable_Entry fasttable[]; -}; +#ifndef UPB_MSG_INT_H_ +#define UPB_MSG_INT_H_ -typedef struct { - upb_MiniTable_Field field; - const upb_MiniTable* extendee; - upb_MiniTable_Sub sub; /* NULL unless submessage or proto2 enum */ -} upb_MiniTable_Extension; +#include +#include -typedef struct { - const upb_MiniTable** msgs; - const upb_MiniTable_Enum** enums; - const upb_MiniTable_Extension** exts; - int msg_count; - int enum_count; - int ext_count; -} upb_MiniTable_File; -// Computes a bitmask in which the |l->required_count| lowest bits are set, -// except that we skip the lowest bit (because upb never uses hasbit 0). -// -// Sample output: -// requiredmask(1) => 0b10 (0x2) -// requiredmask(5) => 0b111110 (0x3e) -UPB_INLINE uint64_t upb_MiniTable_requiredmask(const upb_MiniTable* l) { - int n = l->required_count; - assert(0 < n && n <= 63); - return ((1ULL << n) - 1) << 1; -} +#ifndef UPB_EXTENSION_REGISTRY_H_ +#define UPB_EXTENSION_REGISTRY_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +/* Extension registry: a dynamic data structure that stores a map of: + * (upb_MiniTable, number) -> extension info + * + * upb_decode() uses upb_ExtensionRegistry to look up extensions while parsing + * binary format. + * + * upb_ExtensionRegistry is part of the mini-table (msglayout) family of + * objects. Like all mini-table objects, it is suitable for reflection-less + * builds that do not want to expose names into the binary. + * + * Unlike most mini-table types, upb_ExtensionRegistry requires dynamic memory + * allocation and dynamic initialization: + * * If reflection is being used, then upb_DefPool will construct an appropriate + * upb_ExtensionRegistry automatically. + * * For a mini-table only build, the user must manually construct the + * upb_ExtensionRegistry and populate it with all of the extensions the user + * cares about. + * * A third alternative is to manually unpack relevant extensions after the + * main parse is complete, similar to how Any works. This is perhaps the + * nicest solution from the perspective of reducing dependencies, avoiding + * dynamic memory allocation, and avoiding the need to parse uninteresting + * extensions. The downsides are: + * (1) parse errors are not caught during the main parse + * (2) the CPU hit of parsing comes during access, which could cause an + * undesirable stutter in application performance. + * + * Users cannot directly get or put into this map. Users can only add the + * extensions from a generated module and pass the extension registry to the + * binary decoder. + * + * A upb_DefPool provides a upb_ExtensionRegistry, so any users who use + * reflection do not need to populate a upb_ExtensionRegistry directly. + */ + +typedef struct upb_ExtensionRegistry upb_ExtensionRegistry; -/** upb_ExtensionRegistry *****************************************************/ +// Creates a upb_ExtensionRegistry in the given arena. +// The arena must outlive any use of the extreg. +upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +typedef struct upb_MiniTable upb_MiniTable; +typedef struct upb_MiniTable_Extension upb_MiniTable_Extension; -/* Adds the given extension info for message type |l| and field number |num| - * into the registry. Returns false if this message type and field number were - * already in the map, or if memory allocation fails. */ +// Adds the given extension info for message type |l| and field number |num| +// into the registry. Returns false if this message type and field number were +// already in the map, or if memory allocation fails. bool _upb_extreg_add(upb_ExtensionRegistry* r, const upb_MiniTable_Extension** e, size_t count); -/* Looks up the extension (if any) defined for message type |l| and field - * number |num|. If an extension was found, copies the field info into |*ext| - * and returns true. Otherwise returns false. */ +// Looks up the extension (if any) defined for message type |l| and field +// number |num|. If an extension was found, copies the field info into |*ext| +// and returns true. Otherwise returns false. const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r, const upb_MiniTable* l, uint32_t num); -/** upb_Message ***************************************************************/ - -/* Internal members of a upb_Message that track unknown fields and/or - * extensions. We can change this without breaking binary compatibility. We put - * these before the user's data. The user's upb_Message* points after the - * upb_Message_Internal. */ +#ifdef __cplusplus +} /* extern "C" */ +#endif -typedef struct { - /* Total size of this structure, including the data that follows. - * Must be aligned to 8, which is alignof(upb_Message_Extension) */ - uint32_t size; - /* Offsets relative to the beginning of this structure. - * - * Unknown data grows forward from the beginning to unknown_end. - * Extension data grows backward from size to ext_begin. - * When the two meet, we're out of data and have to realloc. - * - * If we imagine that the final member of this struct is: - * char data[size - overhead]; // overhead = - * sizeof(upb_Message_InternalData) - * - * Then we have: - * unknown data: data[0 .. (unknown_end - overhead)] - * extensions data: data[(ext_begin - overhead) .. (size - overhead)] */ - uint32_t unknown_end; - uint32_t ext_begin; - /* Data follows, as if there were an array: - * char data[size - sizeof(upb_Message_InternalData)]; */ -} upb_Message_InternalData; +#endif /* UPB_EXTENSION_REGISTRY_H_ */ -typedef struct { - upb_Message_InternalData* internal; - /* Message data follows. */ -} upb_Message_Internal; +/* + * upb_table + * + * This header is INTERNAL-ONLY! Its interfaces are not public or stable! + * This file defines very fast int->upb_value (inttable) and string->upb_value + * (strtable) hash tables. + * + * The table uses chained scatter with Brent's variation (inspired by the Lua + * implementation of hash tables). The hash function for strings is Austin + * Appleby's "MurmurHash." + * + * The inttable uses uintptr_t as its key, which guarantees it can be used to + * store pointers or integers of at least 32 bits (upb isn't really useful on + * systems where sizeof(void*) < 4). + * + * The table must be homogeneous (all values of the same type). In debug + * mode, we check this on insert and lookup. + */ -/* Maps upb_CType -> memory size. */ -extern char _upb_CTypeo_size[12]; +#ifndef UPB_INTERNAL_TABLE_H_ +#define UPB_INTERNAL_TABLE_H_ -UPB_INLINE size_t upb_msg_sizeof(const upb_MiniTable* l) { - return l->size + sizeof(upb_Message_Internal); -} +#include -UPB_INLINE upb_Message* _upb_Message_New_inl(const upb_MiniTable* l, - upb_Arena* a) { - size_t size = upb_msg_sizeof(l); - void* mem = upb_Arena_Malloc(a, size); - upb_Message* msg; - if (UPB_UNLIKELY(!mem)) return NULL; - msg = UPB_PTR_AT(mem, sizeof(upb_Message_Internal), upb_Message); - memset(mem, 0, size); - return msg; -} -/* Creates a new messages with the given layout on the given arena. */ -upb_Message* _upb_Message_New(const upb_MiniTable* l, upb_Arena* a); +// Must be last. -UPB_INLINE upb_Message_Internal* upb_Message_Getinternal(upb_Message* msg) { - ptrdiff_t size = sizeof(upb_Message_Internal); - return (upb_Message_Internal*)((char*)msg - size); -} +#ifdef __cplusplus +extern "C" { +#endif -/* Clears the given message. */ -void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l); +/* upb_value ******************************************************************/ -/* Discards the unknown fields for this message only. */ -void _upb_Message_DiscardUnknown_shallow(upb_Message* msg); +typedef struct { + uint64_t val; +} upb_value; -/* Adds unknown data (serialized protobuf data) to the given message. The data - * is copied into the message instance. */ -bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, - upb_Arena* arena); +/* Variant that works with a length-delimited rather than NULL-delimited string, + * as supported by strtable. */ +char* upb_strdup2(const char* s, size_t len, upb_Arena* a); -/** upb_Message_Extension *****************************************************/ +UPB_INLINE void _upb_value_setval(upb_value* v, uint64_t val) { v->val = val; } -/* The internal representation of an extension is self-describing: it contains - * enough information that we can serialize it to binary format without needing - * to look it up in a upb_ExtensionRegistry. +/* For each value ctype, define the following set of functions: * - * This representation allocates 16 bytes to data on 64-bit platforms. This is - * rather wasteful for scalars (in the extreme case of bool, it wastes 15 - * bytes). We accept this because we expect messages to be the most common - * extension type. */ -typedef struct { - const upb_MiniTable_Extension* ext; - union { - upb_StringView str; - void* ptr; - char scalar_data[8]; - } data; -} upb_Message_Extension; - -/* Adds the given extension data to the given message. |ext| is copied into the - * message instance. This logically replaces any previously-added extension with - * this number */ -upb_Message_Extension* _upb_Message_Getorcreateext( - upb_Message* msg, const upb_MiniTable_Extension* ext, upb_Arena* arena); - -/* Returns an array of extensions for this message. Note: the array is - * ordered in reverse relative to the order of creation. */ -const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg, - size_t* count); - -/* Returns an extension for the given field number, or NULL if no extension - * exists for this field number. */ -const upb_Message_Extension* _upb_Message_Getext( - const upb_Message* msg, const upb_MiniTable_Extension* ext); - -void _upb_Message_Clearext(upb_Message* msg, - const upb_MiniTable_Extension* ext); + * // Get/set an int32 from a upb_value. + * int32_t upb_value_getint32(upb_value val); + * void upb_value_setint32(upb_value *val, int32_t cval); + * + * // Construct a new upb_value from an int32. + * upb_value upb_value_int32(int32_t val); */ +#define FUNCS(name, membername, type_t, converter, proto_type) \ + UPB_INLINE void upb_value_set##name(upb_value* val, type_t cval) { \ + val->val = (converter)cval; \ + } \ + UPB_INLINE upb_value upb_value_##name(type_t val) { \ + upb_value ret; \ + upb_value_set##name(&ret, val); \ + return ret; \ + } \ + UPB_INLINE type_t upb_value_get##name(upb_value val) { \ + return (type_t)(converter)val.val; \ + } -void _upb_Message_Clearext(upb_Message* msg, - const upb_MiniTable_Extension* ext); +FUNCS(int32, int32, int32_t, int32_t, UPB_CTYPE_INT32) +FUNCS(int64, int64, int64_t, int64_t, UPB_CTYPE_INT64) +FUNCS(uint32, uint32, uint32_t, uint32_t, UPB_CTYPE_UINT32) +FUNCS(uint64, uint64, uint64_t, uint64_t, UPB_CTYPE_UINT64) +FUNCS(bool, _bool, bool, bool, UPB_CTYPE_BOOL) +FUNCS(cstr, cstr, char*, uintptr_t, UPB_CTYPE_CSTR) +FUNCS(ptr, ptr, void*, uintptr_t, UPB_CTYPE_PTR) +FUNCS(constptr, constptr, const void*, uintptr_t, UPB_CTYPE_CONSTPTR) -/** Hasbit access *************************************************************/ +#undef FUNCS -UPB_INLINE bool _upb_hasbit(const upb_Message* msg, size_t idx) { - return (*UPB_PTR_AT(msg, idx / 8, const char) & (1 << (idx % 8))) != 0; +UPB_INLINE void upb_value_setfloat(upb_value* val, float cval) { + memcpy(&val->val, &cval, sizeof(cval)); } -UPB_INLINE void _upb_sethas(const upb_Message* msg, size_t idx) { - (*UPB_PTR_AT(msg, idx / 8, char)) |= (char)(1 << (idx % 8)); +UPB_INLINE void upb_value_setdouble(upb_value* val, double cval) { + memcpy(&val->val, &cval, sizeof(cval)); } -UPB_INLINE void _upb_clearhas(const upb_Message* msg, size_t idx) { - (*UPB_PTR_AT(msg, idx / 8, char)) &= (char)(~(1 << (idx % 8))); +UPB_INLINE upb_value upb_value_float(float cval) { + upb_value ret; + upb_value_setfloat(&ret, cval); + return ret; } -UPB_INLINE size_t _upb_Message_Hasidx(const upb_MiniTable_Field* f) { - UPB_ASSERT(f->presence > 0); - return f->presence; +UPB_INLINE upb_value upb_value_double(double cval) { + upb_value ret; + upb_value_setdouble(&ret, cval); + return ret; } -UPB_INLINE bool _upb_hasbit_field(const upb_Message* msg, - const upb_MiniTable_Field* f) { - return _upb_hasbit(msg, _upb_Message_Hasidx(f)); -} +#undef SET_TYPE -UPB_INLINE void _upb_sethas_field(const upb_Message* msg, - const upb_MiniTable_Field* f) { - _upb_sethas(msg, _upb_Message_Hasidx(f)); +/* upb_tabkey *****************************************************************/ + +/* Either: + * 1. an actual integer key, or + * 2. a pointer to a string prefixed by its uint32_t length, owned by us. + * + * ...depending on whether this is a string table or an int table. We would + * make this a union of those two types, but C89 doesn't support statically + * initializing a non-first union member. */ +typedef uintptr_t upb_tabkey; + +UPB_INLINE char* upb_tabstr(upb_tabkey key, uint32_t* len) { + char* mem = (char*)key; + if (len) memcpy(len, mem, sizeof(*len)); + return mem + sizeof(*len); } -UPB_INLINE void _upb_clearhas_field(const upb_Message* msg, - const upb_MiniTable_Field* f) { - _upb_clearhas(msg, _upb_Message_Hasidx(f)); +UPB_INLINE upb_StringView upb_tabstrview(upb_tabkey key) { + upb_StringView ret; + uint32_t len; + ret.data = upb_tabstr(key, &len); + ret.size = len; + return ret; } -/** Oneof case access *********************************************************/ +/* upb_tabval *****************************************************************/ -UPB_INLINE uint32_t* _upb_oneofcase(upb_Message* msg, size_t case_ofs) { - return UPB_PTR_AT(msg, case_ofs, uint32_t); -} +typedef struct upb_tabval { + uint64_t val; +} upb_tabval; -UPB_INLINE uint32_t _upb_getoneofcase(const void* msg, size_t case_ofs) { - return *UPB_PTR_AT(msg, case_ofs, uint32_t); -} +#define UPB_TABVALUE_EMPTY_INIT \ + { -1 } -UPB_INLINE size_t _upb_oneofcase_ofs(const upb_MiniTable_Field* f) { - UPB_ASSERT(f->presence < 0); - return ~(ptrdiff_t)f->presence; -} +/* upb_table ******************************************************************/ -UPB_INLINE uint32_t* _upb_oneofcase_field(upb_Message* msg, - const upb_MiniTable_Field* f) { - return _upb_oneofcase(msg, _upb_oneofcase_ofs(f)); -} +typedef struct _upb_tabent { + upb_tabkey key; + upb_tabval val; -UPB_INLINE uint32_t _upb_getoneofcase_field(const upb_Message* msg, - const upb_MiniTable_Field* f) { - return _upb_getoneofcase(msg, _upb_oneofcase_ofs(f)); -} + /* Internal chaining. This is const so we can create static initializers for + * tables. We cast away const sometimes, but *only* when the containing + * upb_table is known to be non-const. This requires a bit of care, but + * the subtlety is confined to table.c. */ + const struct _upb_tabent* next; +} upb_tabent; -UPB_INLINE bool _upb_has_submsg_nohasbit(const upb_Message* msg, size_t ofs) { - return *UPB_PTR_AT(msg, ofs, const upb_Message*) != NULL; -} +typedef struct { + size_t count; /* Number of entries in the hash part. */ + uint32_t mask; /* Mask to turn hash value -> bucket. */ + uint32_t max_count; /* Max count before we hit our load limit. */ + uint8_t size_lg2; /* Size of the hashtable part is 2^size_lg2 entries. */ + upb_tabent* entries; +} upb_table; -/** upb_Array *****************************************************************/ +typedef struct { + upb_table t; +} upb_strtable; -/* Our internal representation for repeated fields. */ typedef struct { - uintptr_t data; /* Tagged ptr: low 3 bits of ptr are lg2(elem size). */ - size_t len; /* Measured in elements. */ - size_t size; /* Measured in elements. */ - uint64_t junk; -} upb_Array; + upb_table t; /* For entries that don't fit in the array part. */ + const upb_tabval* array; /* Array part of the table. See const note above. */ + size_t array_size; /* Array part size. */ + size_t array_count; /* Array part number of elements. */ +} upb_inttable; -UPB_INLINE const void* _upb_array_constptr(const upb_Array* arr) { - UPB_ASSERT((arr->data & 7) <= 4); - return (void*)(arr->data & ~(uintptr_t)7); +UPB_INLINE size_t upb_table_size(const upb_table* t) { + if (t->size_lg2 == 0) + return 0; + else + return 1 << t->size_lg2; } -UPB_INLINE uintptr_t _upb_array_tagptr(void* ptr, int elem_size_lg2) { - UPB_ASSERT(elem_size_lg2 <= 4); - return (uintptr_t)ptr | elem_size_lg2; -} +/* Internal-only functions, in .h file only out of necessity. */ +UPB_INLINE bool upb_tabent_isempty(const upb_tabent* e) { return e->key == 0; } -UPB_INLINE void* _upb_array_ptr(upb_Array* arr) { - return (void*)_upb_array_constptr(arr); -} +/* Initialize and uninitialize a table, respectively. If memory allocation + * failed, false is returned that the table is uninitialized. */ +bool upb_inttable_init(upb_inttable* table, upb_Arena* a); +bool upb_strtable_init(upb_strtable* table, size_t expected_size, upb_Arena* a); -UPB_INLINE uintptr_t _upb_tag_arrptr(void* ptr, int elem_size_lg2) { - UPB_ASSERT(elem_size_lg2 <= 4); - UPB_ASSERT(((uintptr_t)ptr & 7) == 0); - return (uintptr_t)ptr | (unsigned)elem_size_lg2; +/* Returns the number of values in the table. */ +size_t upb_inttable_count(const upb_inttable* t); +UPB_INLINE size_t upb_strtable_count(const upb_strtable* t) { + return t->t.count; } -UPB_INLINE upb_Array* _upb_Array_New(upb_Arena* a, size_t init_size, - int elem_size_lg2) { - const size_t arr_size = UPB_ALIGN_UP(sizeof(upb_Array), 8); - const size_t bytes = sizeof(upb_Array) + (init_size << elem_size_lg2); - upb_Array* arr = (upb_Array*)upb_Arena_Malloc(a, bytes); - if (!arr) return NULL; - arr->data = _upb_tag_arrptr(UPB_PTR_AT(arr, arr_size, void), elem_size_lg2); - arr->len = 0; - arr->size = init_size; - return arr; -} +void upb_strtable_clear(upb_strtable* t); -/* Resizes the capacity of the array to be at least min_size. */ -bool _upb_array_realloc(upb_Array* arr, size_t min_size, upb_Arena* arena); +/* Inserts the given key into the hashtable with the given value. The key must + * not already exist in the hash table. For strtables, the key is not required + * to be NULL-terminated, and the table will make an internal copy of the key. + * Inttables must not insert a value of UINTPTR_MAX. + * + * If a table resize was required but memory allocation failed, false is + * returned and the table is unchanged. */ +bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, + upb_Arena* a); +bool upb_strtable_insert(upb_strtable* t, const char* key, size_t len, + upb_value val, upb_Arena* a); -/* Fallback functions for when the accessors require a resize. */ -void* _upb_Array_Resize_fallback(upb_Array** arr_ptr, size_t size, - int elem_size_lg2, upb_Arena* arena); -bool _upb_Array_Append_fallback(upb_Array** arr_ptr, const void* value, - int elem_size_lg2, upb_Arena* arena); +/* Looks up key in this table, returning "true" if the key was found. + * If v is non-NULL, copies the value for this key into *v. */ +bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v); +bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, + upb_value* v); -UPB_INLINE bool _upb_array_reserve(upb_Array* arr, size_t size, - upb_Arena* arena) { - if (arr->size < size) return _upb_array_realloc(arr, size, arena); - return true; +/* For NULL-terminated strings. */ +UPB_INLINE bool upb_strtable_lookup(const upb_strtable* t, const char* key, + upb_value* v) { + return upb_strtable_lookup2(t, key, strlen(key), v); } -UPB_INLINE bool _upb_Array_Resize(upb_Array* arr, size_t size, - upb_Arena* arena) { - if (!_upb_array_reserve(arr, size, arena)) return false; - arr->len = size; - return true; -} +/* Removes an item from the table. Returns true if the remove was successful, + * and stores the removed item in *val if non-NULL. */ +bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val); +bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, + upb_value* val); -UPB_INLINE const void* _upb_array_accessor(const void* msg, size_t ofs, - size_t* size) { - const upb_Array* arr = *UPB_PTR_AT(msg, ofs, const upb_Array*); - if (arr) { - if (size) *size = arr->len; - return _upb_array_constptr(arr); - } else { - if (size) *size = 0; - return NULL; - } +UPB_INLINE bool upb_strtable_remove(upb_strtable* t, const char* key, + upb_value* v) { + return upb_strtable_remove2(t, key, strlen(key), v); } -UPB_INLINE void* _upb_array_mutable_accessor(void* msg, size_t ofs, - size_t* size) { - upb_Array* arr = *UPB_PTR_AT(msg, ofs, upb_Array*); - if (arr) { - if (size) *size = arr->len; - return _upb_array_ptr(arr); - } else { - if (size) *size = 0; - return NULL; - } -} +/* Updates an existing entry in an inttable. If the entry does not exist, + * returns false and does nothing. Unlike insert/remove, this does not + * invalidate iterators. */ +bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val); -UPB_INLINE void* _upb_Array_Resize_accessor2(void* msg, size_t ofs, size_t size, - int elem_size_lg2, - upb_Arena* arena) { - upb_Array** arr_ptr = UPB_PTR_AT(msg, ofs, upb_Array*); - upb_Array* arr = *arr_ptr; - if (!arr || arr->size < size) { - return _upb_Array_Resize_fallback(arr_ptr, size, elem_size_lg2, arena); - } - arr->len = size; - return _upb_array_ptr(arr); -} +/* Optimizes the table for the current set of entries, for both memory use and + * lookup time. Client should call this after all entries have been inserted; + * inserting more entries is legal, but will likely require a table resize. */ +void upb_inttable_compact(upb_inttable* t, upb_Arena* a); -UPB_INLINE bool _upb_Array_Append_accessor2(void* msg, size_t ofs, - int elem_size_lg2, - const void* value, - upb_Arena* arena) { - upb_Array** arr_ptr = UPB_PTR_AT(msg, ofs, upb_Array*); - size_t elem_size = 1 << elem_size_lg2; - upb_Array* arr = *arr_ptr; - void* ptr; - if (!arr || arr->len == arr->size) { - return _upb_Array_Append_fallback(arr_ptr, value, elem_size_lg2, arena); - } - ptr = _upb_array_ptr(arr); - memcpy(UPB_PTR_AT(ptr, arr->len * elem_size, char), value, elem_size); - arr->len++; - return true; -} +/* Exposed for testing only. */ +bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a); -/* Used by old generated code, remove once all code has been regenerated. */ -UPB_INLINE int _upb_sizelg2(upb_CType type) { - switch (type) { - case kUpb_CType_Bool: - return 0; - case kUpb_CType_Float: - case kUpb_CType_Int32: - case kUpb_CType_UInt32: - case kUpb_CType_Enum: - return 2; - case kUpb_CType_Message: - return UPB_SIZE(2, 3); - case kUpb_CType_Double: - case kUpb_CType_Int64: - case kUpb_CType_UInt64: - return 3; - case kUpb_CType_String: - case kUpb_CType_Bytes: - return UPB_SIZE(3, 4); - } - UPB_UNREACHABLE(); -} -UPB_INLINE void* _upb_Array_Resize_accessor(void* msg, size_t ofs, size_t size, - upb_CType type, upb_Arena* arena) { - return _upb_Array_Resize_accessor2(msg, ofs, size, _upb_sizelg2(type), arena); -} -UPB_INLINE bool _upb_Array_Append_accessor(void* msg, size_t ofs, - size_t elem_size, upb_CType type, - const void* value, - upb_Arena* arena) { - (void)elem_size; - return _upb_Array_Append_accessor2(msg, ofs, _upb_sizelg2(type), value, - arena); -} +/* Iterators ******************************************************************/ -/** upb_Map *******************************************************************/ +/* Iteration over inttable. + * + * intptr_t iter = UPB_INTTABLE_BEGIN; + * uintptr_t key; + * upb_value val; + * while (upb_inttable_next2(t, &key, &val, &iter)) { + * // ... + * } + */ -/* Right now we use strmaps for everything. We'll likely want to use - * integer-specific maps for integer-keyed maps.*/ -typedef struct { - /* Size of key and val, based on the map type. Strings are represented as '0' - * because they must be handled specially. */ - char key_size; - char val_size; +#define UPB_INTTABLE_BEGIN -1 - upb_strtable table; -} upb_Map; +bool upb_inttable_next2(const upb_inttable* t, uintptr_t* key, upb_value* val, + intptr_t* iter); +void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter); -/* Map entries aren't actually stored, they are only used during parsing. For - * parsing, it helps a lot if all map entry messages have the same layout. - * The compiler and def.c must ensure that all map entries have this layout. */ -typedef struct { - upb_Message_Internal internal; - union { - upb_StringView str; /* For str/bytes. */ - upb_value val; /* For all other types. */ - } k; - union { - upb_StringView str; /* For str/bytes. */ - upb_value val; /* For all other types. */ - } v; -} upb_MapEntry; +/* Iteration over strtable. + * + * intptr_t iter = UPB_INTTABLE_BEGIN; + * upb_StringView key; + * upb_value val; + * while (upb_strtable_next2(t, &key, &val, &iter)) { + * // ... + * } + */ -/* Creates a new map on the given arena with this key/value type. */ -upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size); +#define UPB_STRTABLE_BEGIN -1 -/* Converting between internal table representation and user values. +bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key, + upb_value* val, intptr_t* iter); +void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter); + +/* DEPRECATED iterators, slated for removal. * - * _upb_map_tokey() and _upb_map_fromkey() are inverses. - * _upb_map_tovalue() and _upb_map_fromvalue() are inverses. + * Iterators for int and string tables. We are subject to some kind of unusual + * design constraints: * - * These functions account for the fact that strings are treated differently - * from other types when stored in a map. + * For high-level languages: + * - we must be able to guarantee that we don't crash or corrupt memory even if + * the program accesses an invalidated iterator. + * + * For C++11 range-based for: + * - iterators must be copyable + * - iterators must be comparable + * - it must be possible to construct an "end" value. + * + * Iteration order is undefined. + * + * Modifying the table invalidates iterators. upb_{str,int}table_done() is + * guaranteed to work even on an invalidated iterator, as long as the table it + * is iterating over has not been freed. Calling next() or accessing data from + * an invalidated iterator yields unspecified elements from the table, but it is + * guaranteed not to crash and to return real table elements (except when done() + * is true). */ + +/* upb_strtable_iter **********************************************************/ + +/* upb_strtable_iter i; + * upb_strtable_begin(&i, t); + * for(; !upb_strtable_done(&i); upb_strtable_next(&i)) { + * const char *key = upb_strtable_iter_key(&i); + * const upb_value val = upb_strtable_iter_value(&i); + * // ... + * } */ -UPB_INLINE upb_StringView _upb_map_tokey(const void* key, size_t size) { - if (size == UPB_MAPTYPE_STRING) { - return *(upb_StringView*)key; - } else { - return upb_StringView_FromDataAndSize((const char*)key, size); - } -} +typedef struct { + const upb_strtable* t; + size_t index; +} upb_strtable_iter; -UPB_INLINE void _upb_map_fromkey(upb_StringView key, void* out, size_t size) { - if (size == UPB_MAPTYPE_STRING) { - memcpy(out, &key, sizeof(key)); - } else { - memcpy(out, key.data, size); - } -} +void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t); +void upb_strtable_next(upb_strtable_iter* i); +bool upb_strtable_done(const upb_strtable_iter* i); +upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i); +upb_value upb_strtable_iter_value(const upb_strtable_iter* i); +void upb_strtable_iter_setdone(upb_strtable_iter* i); +bool upb_strtable_iter_isequal(const upb_strtable_iter* i1, + const upb_strtable_iter* i2); -UPB_INLINE bool _upb_map_tovalue(const void* val, size_t size, - upb_value* msgval, upb_Arena* a) { - if (size == UPB_MAPTYPE_STRING) { - upb_StringView* strp = (upb_StringView*)upb_Arena_Malloc(a, sizeof(*strp)); - if (!strp) return false; - *strp = *(upb_StringView*)val; - *msgval = upb_value_ptr(strp); - } else { - memcpy(msgval, val, size); - } - return true; -} +/* upb_inttable_iter **********************************************************/ -UPB_INLINE void _upb_map_fromvalue(upb_value val, void* out, size_t size) { - if (size == UPB_MAPTYPE_STRING) { - const upb_StringView* strp = (const upb_StringView*)upb_value_getptr(val); - memcpy(out, strp, sizeof(upb_StringView)); - } else { - memcpy(out, &val, size); - } -} +/* upb_inttable_iter i; + * upb_inttable_begin(&i, t); + * for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { + * uintptr_t key = upb_inttable_iter_key(&i); + * upb_value val = upb_inttable_iter_value(&i); + * // ... + * } + */ -/* Map operations, shared by reflection and generated code. */ +typedef struct { + const upb_inttable* t; + size_t index; + bool array_part; +} upb_inttable_iter; -UPB_INLINE size_t _upb_Map_Size(const upb_Map* map) { - return map->table.t.count; +UPB_INLINE const upb_tabent* str_tabent(const upb_strtable_iter* i) { + return &i->t->t.entries[i->index]; } -UPB_INLINE bool _upb_Map_Get(const upb_Map* map, const void* key, - size_t key_size, void* val, size_t val_size) { - upb_value tabval; - upb_StringView k = _upb_map_tokey(key, key_size); - bool ret = upb_strtable_lookup2(&map->table, k.data, k.size, &tabval); - if (ret && val) { - _upb_map_fromvalue(tabval, val, val_size); - } - return ret; -} +void upb_inttable_begin(upb_inttable_iter* i, const upb_inttable* t); +void upb_inttable_next(upb_inttable_iter* i); +bool upb_inttable_done(const upb_inttable_iter* i); +uintptr_t upb_inttable_iter_key(const upb_inttable_iter* i); +upb_value upb_inttable_iter_value(const upb_inttable_iter* i); +void upb_inttable_iter_setdone(upb_inttable_iter* i); +bool upb_inttable_iter_isequal(const upb_inttable_iter* i1, + const upb_inttable_iter* i2); -UPB_INLINE void* _upb_map_next(const upb_Map* map, size_t* iter) { - upb_strtable_iter it; - it.t = &map->table; - it.index = *iter; - upb_strtable_next(&it); - *iter = it.index; - if (upb_strtable_done(&it)) return NULL; - return (void*)str_tabent(&it); -} +uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed); -UPB_INLINE bool _upb_Map_Set(upb_Map* map, const void* key, size_t key_size, - void* val, size_t val_size, upb_Arena* a) { - upb_StringView strkey = _upb_map_tokey(key, key_size); - upb_value tabval = {0}; - if (!_upb_map_tovalue(val, val_size, &tabval, a)) return false; +#ifdef __cplusplus +} /* extern "C" */ +#endif - /* TODO(haberman): add overwrite operation to minimize number of lookups. */ - upb_strtable_remove2(&map->table, strkey.data, strkey.size, NULL); - return upb_strtable_insert(&map->table, strkey.data, strkey.size, tabval, a); -} -UPB_INLINE bool _upb_Map_Delete(upb_Map* map, const void* key, - size_t key_size) { - upb_StringView k = _upb_map_tokey(key, key_size); - return upb_strtable_remove2(&map->table, k.data, k.size, NULL); -} +#endif /* UPB_INTERNAL_TABLE_H_ */ -UPB_INLINE void _upb_Map_Clear(upb_Map* map) { - upb_strtable_clear(&map->table); -} +// Must be last. -/* Message map operations, these get the map from the message first. */ +#ifdef __cplusplus +extern "C" { +#endif -UPB_INLINE size_t _upb_msg_map_size(const upb_Message* msg, size_t ofs) { - upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); - return map ? _upb_Map_Size(map) : 0; -} +/** upb_*Int* conversion routines ********************************************/ -UPB_INLINE bool _upb_msg_map_get(const upb_Message* msg, size_t ofs, - const void* key, size_t key_size, void* val, - size_t val_size) { - upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); - if (!map) return false; - return _upb_Map_Get(map, key, key_size, val, val_size); -} +UPB_INLINE int32_t _upb_Int32_FromI(int v) { return (int32_t)v; } -UPB_INLINE void* _upb_msg_map_next(const upb_Message* msg, size_t ofs, - size_t* iter) { - upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); - if (!map) return NULL; - return _upb_map_next(map, iter); -} +UPB_INLINE int64_t _upb_Int64_FromLL(long long v) { return (int64_t)v; } -UPB_INLINE bool _upb_msg_map_set(upb_Message* msg, size_t ofs, const void* key, - size_t key_size, void* val, size_t val_size, - upb_Arena* arena) { - upb_Map** map = UPB_PTR_AT(msg, ofs, upb_Map*); - if (!*map) { - *map = _upb_Map_New(arena, key_size, val_size); - } - return _upb_Map_Set(*map, key, key_size, val, val_size, arena); -} +UPB_INLINE uint32_t _upb_UInt32_FromU(unsigned v) { return (uint32_t)v; } -UPB_INLINE bool _upb_msg_map_delete(upb_Message* msg, size_t ofs, - const void* key, size_t key_size) { - upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); - if (!map) return false; - return _upb_Map_Delete(map, key, key_size); +UPB_INLINE uint64_t _upb_UInt64_FromULL(unsigned long long v) { + return (uint64_t)v; } -UPB_INLINE void _upb_msg_map_clear(upb_Message* msg, size_t ofs) { - upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); - if (!map) return; - _upb_Map_Clear(map); -} +extern const float kUpb_FltInfinity; +extern const double kUpb_Infinity; -/* Accessing map key/value from a pointer, used by generated code only. */ +/** upb_MiniTable *************************************************************/ -UPB_INLINE void _upb_msg_map_key(const void* msg, void* key, size_t size) { - const upb_tabent* ent = (const upb_tabent*)msg; - uint32_t u32len; - upb_StringView k; - k.data = upb_tabstr(ent->key, &u32len); - k.size = u32len; - _upb_map_fromkey(k, key, size); -} +/* upb_MiniTable represents the memory layout of a given upb_MessageDef. The + * members are public so generated code can initialize them, but users MUST NOT + * read or write any of its members. */ -UPB_INLINE void _upb_msg_map_value(const void* msg, void* val, size_t size) { - const upb_tabent* ent = (const upb_tabent*)msg; - upb_value v = {ent->val.val}; - _upb_map_fromvalue(v, val, size); -} +typedef struct { + uint32_t number; + uint16_t offset; + int16_t presence; // If >0, hasbit_index. If <0, ~oneof_index + uint16_t submsg_index; // kUpb_NoSub if descriptortype != MESSAGE/GROUP/ENUM + uint8_t descriptortype; + uint8_t mode; /* upb_FieldMode | upb_LabelFlags | + (upb_FieldRep << kUpb_FieldRep_Shift) */ +} upb_MiniTable_Field; -UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, - size_t size) { - upb_tabent* ent = (upb_tabent*)msg; - /* This is like _upb_map_tovalue() except the entry already exists so we can - * reuse the allocated upb_StringView for string fields. */ - if (size == UPB_MAPTYPE_STRING) { - upb_StringView* strp = (upb_StringView*)(uintptr_t)ent->val.val; - memcpy(strp, val, sizeof(*strp)); - } else { - memcpy(&ent->val.val, val, size); - } -} +#define kUpb_NoSub ((uint16_t)-1) -/** _upb_mapsorter ************************************************************/ +typedef enum { + kUpb_FieldMode_Map = 0, + kUpb_FieldMode_Array = 1, + kUpb_FieldMode_Scalar = 2, +} upb_FieldMode; -/* _upb_mapsorter sorts maps and provides ordered iteration over the entries. - * Since maps can be recursive (map values can be messages which contain other - * maps). _upb_mapsorter can contain a stack of maps. */ +// Mask to isolate the upb_FieldMode from field.mode. +#define kUpb_FieldMode_Mask 3 -typedef struct { - upb_tabent const** entries; - int size; - int cap; -} _upb_mapsorter; +/* Extra flags on the mode field. */ +typedef enum { + kUpb_LabelFlags_IsPacked = 4, + kUpb_LabelFlags_IsExtension = 8, +} upb_LabelFlags; -typedef struct { - int start; - int pos; - int end; -} _upb_sortedmap; +// Note: we sort by this number when calculating layout order. +typedef enum { + kUpb_FieldRep_1Byte = 0, + kUpb_FieldRep_4Byte = 1, + kUpb_FieldRep_StringView = 2, + kUpb_FieldRep_Pointer = 3, + kUpb_FieldRep_8Byte = 4, -UPB_INLINE void _upb_mapsorter_init(_upb_mapsorter* s) { - s->entries = NULL; - s->size = 0; - s->cap = 0; -} + kUpb_FieldRep_Shift = 5, // Bit offset of the rep in upb_MiniTable_Field.mode + kUpb_FieldRep_Max = kUpb_FieldRep_8Byte, +} upb_FieldRep; -UPB_INLINE void _upb_mapsorter_destroy(_upb_mapsorter* s) { - if (s->entries) free(s->entries); +UPB_INLINE upb_FieldMode upb_FieldMode_Get(const upb_MiniTable_Field* field) { + return (upb_FieldMode)(field->mode & 3); } -bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, - const upb_Map* map, _upb_sortedmap* sorted); - -UPB_INLINE void _upb_mapsorter_popmap(_upb_mapsorter* s, - _upb_sortedmap* sorted) { - s->size = sorted->start; +UPB_INLINE bool upb_IsRepeatedOrMap(const upb_MiniTable_Field* field) { + /* This works because upb_FieldMode has no value 3. */ + return !(field->mode & kUpb_FieldMode_Scalar); } -UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter* s, const upb_Map* map, - _upb_sortedmap* sorted, upb_MapEntry* ent) { - if (sorted->pos == sorted->end) return false; - const upb_tabent* tabent = s->entries[sorted->pos++]; - upb_StringView key = upb_tabstrview(tabent->key); - _upb_map_fromkey(key, &ent->k, map->key_size); - upb_value val = {tabent->val.val}; - _upb_map_fromvalue(val, &ent->v, map->val_size); - return true; +UPB_INLINE bool upb_IsSubMessage(const upb_MiniTable_Field* field) { + return field->descriptortype == kUpb_FieldType_Message || + field->descriptortype == kUpb_FieldType_Group; } -#ifdef __cplusplus -} /* extern "C" */ -#endif +struct upb_Decoder; +struct upb_MiniTable; +typedef const char* _upb_FieldParser(struct upb_Decoder* d, const char* ptr, + upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t data); -#endif /* UPB_MSG_INT_H_ */ +typedef struct { + uint64_t field_data; + _upb_FieldParser* field_parser; +} _upb_FastTable_Entry; -/** upb/upb_internal.h ************************************************************/ -#ifndef UPB_INT_H_ -#define UPB_INT_H_ +typedef struct { + uint32_t mask_limit; // Limit enum value that can be tested with mask. + uint32_t value_count; // Number of values after the bitfield. + uint32_t data[]; // Bitmask + enumerated values follow. +} upb_MiniTable_Enum; +typedef enum { + _kUpb_FastEnumCheck_ValueIsInEnum = 0, + _kUpb_FastEnumCheck_ValueIsNotInEnum = 1, + _kUpb_FastEnumCheck_CannotCheckFast = 2, +} _kUpb_FastEnumCheck_Status; + +UPB_INLINE _kUpb_FastEnumCheck_Status +_upb_MiniTable_CheckEnumValueFast(const upb_MiniTable_Enum* e, uint32_t val) { + if (UPB_UNLIKELY(val >= 64)) return _kUpb_FastEnumCheck_CannotCheckFast; + uint64_t mask = e->data[0] | ((uint64_t)e->data[1] << 32); + return (mask & (1ULL << val)) ? _kUpb_FastEnumCheck_ValueIsInEnum + : _kUpb_FastEnumCheck_ValueIsNotInEnum; +} + +UPB_INLINE bool _upb_MiniTable_CheckEnumValueSlow(const upb_MiniTable_Enum* e, + uint32_t val) { + if (val < e->mask_limit) return e->data[val / 32] & (1ULL << (val % 32)); + // OPT: binary search long lists? + const uint32_t* start = &e->data[e->mask_limit / 32]; + const uint32_t* limit = &e->data[(e->mask_limit / 32) + e->value_count]; + for (const uint32_t* p = start; p < limit; p++) { + if (*p == val) return true; + } + return false; +} -struct mem_block; -typedef struct mem_block mem_block; +// Validates enum value against range defined by enum mini table. +UPB_INLINE bool upb_MiniTable_Enum_CheckValue(const upb_MiniTable_Enum* e, + uint32_t val) { + _kUpb_FastEnumCheck_Status status = _upb_MiniTable_CheckEnumValueFast(e, val); + if (UPB_UNLIKELY(status == _kUpb_FastEnumCheck_CannotCheckFast)) { + return _upb_MiniTable_CheckEnumValueSlow(e, val); + } + return status == _kUpb_FastEnumCheck_ValueIsInEnum ? true : false; +} -struct upb_Arena { - _upb_ArenaHead head; - /* Stores cleanup metadata for this arena. - * - a pointer to the current cleanup counter. - * - a boolean indicating if there is an unowned initial block. */ - uintptr_t cleanup_metadata; +typedef union { + const struct upb_MiniTable* submsg; + const upb_MiniTable_Enum* subenum; +} upb_MiniTable_Sub; - /* Allocator to allocate arena blocks. We are responsible for freeing these - * when we are destroyed. */ - upb_alloc* block_alloc; - uint32_t last_size; +typedef enum { + kUpb_ExtMode_NonExtendable = 0, // Non-extendable message. + kUpb_ExtMode_Extendable = 1, // Normal extendable message. + kUpb_ExtMode_IsMessageSet = 2, // MessageSet message. + kUpb_ExtMode_IsMessageSet_ITEM = + 3, // MessageSet item (temporary only, see decode.c) - /* When multiple arenas are fused together, each arena points to a parent - * arena (root points to itself). The root tracks how many live arenas - * reference it. */ - uint32_t refcount; /* Only used when a->parent == a */ - struct upb_Arena* parent; + // During table building we steal a bit to indicate that the message is a map + // entry. *Only* used during table building! + kUpb_ExtMode_IsMapEntry = 4, +} upb_ExtMode; - /* Linked list of blocks to free/cleanup. */ - mem_block *freelist, *freelist_tail; +/* MessageSet wire format is: + * message MessageSet { + * repeated group Item = 1 { + * required int32 type_id = 2; + * required bytes message = 3; + * } + * } + */ +typedef enum { + _UPB_MSGSET_ITEM = 1, + _UPB_MSGSET_TYPEID = 2, + _UPB_MSGSET_MESSAGE = 3, +} upb_msgext_fieldnum; + +struct upb_MiniTable { + const upb_MiniTable_Sub* subs; + const upb_MiniTable_Field* fields; + /* Must be aligned to sizeof(void*). Doesn't include internal members like + * unknown fields, extension dict, pointer to msglayout, etc. */ + uint16_t size; + uint16_t field_count; + uint8_t ext; // upb_ExtMode, declared as uint8_t so sizeof(ext) == 1 + uint8_t dense_below; + uint8_t table_mask; + uint8_t required_count; // Required fields have the lowest hasbits. + /* To statically initialize the tables of variable length, we need a flexible + * array member, and we need to compile in gnu99 mode (constant initialization + * of flexible array members is a GNU extension, not in C99 unfortunately. */ + _upb_FastTable_Entry fasttable[]; }; -// Encodes a float or double that is round-trippable, but as short as possible. -// These routines are not fully optimal (not guaranteed to be shortest), but are -// short-ish and match the implementation that has been used in protobuf since -// the beginning. -// -// The given buffer size must be at least kUpb_RoundTripBufferSize. -enum { kUpb_RoundTripBufferSize = 32 }; -void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size); -void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size); +typedef struct upb_MiniTable_Extension upb_MiniTable_Extension; -#endif /* UPB_INT_H_ */ +struct upb_MiniTable_Extension { + upb_MiniTable_Field field; + const upb_MiniTable* extendee; + upb_MiniTable_Sub sub; /* NULL unless submessage or proto2 enum */ +}; -/* Must be last. */ +typedef struct { + const upb_MiniTable** msgs; + const upb_MiniTable_Enum** enums; + const upb_MiniTable_Extension** exts; + int msg_count; + int enum_count; + int ext_count; +} upb_MiniTable_File; -#define DECODE_NOGROUP (uint32_t) - 1 - -typedef struct upb_Decoder { - const char* end; /* Can read up to 16 bytes slop beyond this. */ - const char* limit_ptr; /* = end + UPB_MIN(limit, 0) */ - upb_Message* unknown_msg; /* If non-NULL, add unknown data at buffer flip. */ - const char* unknown; /* Start of unknown data. */ - const upb_ExtensionRegistry* - extreg; /* For looking up extensions during the parse. */ - int limit; /* Submessage limit relative to end. */ - int depth; /* Tracks recursion depth to bound stack usage. */ - uint32_t end_group; /* field number of END_GROUP tag, else DECODE_NOGROUP */ - uint16_t options; - bool missing_required; - char patch[32]; - upb_Arena arena; - jmp_buf err; +// Computes a bitmask in which the |l->required_count| lowest bits are set, +// except that we skip the lowest bit (because upb never uses hasbit 0). +// +// Sample output: +// requiredmask(1) => 0b10 (0x2) +// requiredmask(5) => 0b111110 (0x3e) +UPB_INLINE uint64_t upb_MiniTable_requiredmask(const upb_MiniTable* l) { + int n = l->required_count; + assert(0 < n && n <= 63); + return ((1ULL << n) - 1) << 1; +} -#ifndef NDEBUG - const char* debug_tagstart; - const char* debug_valstart; -#endif -} upb_Decoder; +/** upb_Message ***************************************************************/ -/* Error function that will abort decoding with longjmp(). We can't declare this - * UPB_NORETURN, even though it is appropriate, because if we do then compilers - * will "helpfully" refuse to tailcall to it - * (see: https://stackoverflow.com/a/55657013), which will defeat a major goal - * of our optimizations. That is also why we must declare it in a separate file, - * otherwise the compiler will see that it calls longjmp() and deduce that it is - * noreturn. */ -const char* fastdecode_err(upb_Decoder* d, int status); +/* Internal members of a upb_Message that track unknown fields and/or + * extensions. We can change this without breaking binary compatibility. We put + * these before the user's data. The user's upb_Message* points after the + * upb_Message_Internal. */ -extern const uint8_t upb_utf8_offsets[]; +typedef struct { + /* Total size of this structure, including the data that follows. + * Must be aligned to 8, which is alignof(upb_Message_Extension) */ + uint32_t size; -UPB_INLINE -bool decode_verifyutf8_inl(const char* ptr, int len) { - const char* end = ptr + len; + /* Offsets relative to the beginning of this structure. + * + * Unknown data grows forward from the beginning to unknown_end. + * Extension data grows backward from size to ext_begin. + * When the two meet, we're out of data and have to realloc. + * + * If we imagine that the final member of this struct is: + * char data[size - overhead]; // overhead = + * sizeof(upb_Message_InternalData) + * + * Then we have: + * unknown data: data[0 .. (unknown_end - overhead)] + * extensions data: data[(ext_begin - overhead) .. (size - overhead)] */ + uint32_t unknown_end; + uint32_t ext_begin; + /* Data follows, as if there were an array: + * char data[size - sizeof(upb_Message_InternalData)]; */ +} upb_Message_InternalData; - // Check 8 bytes at a time for any non-ASCII char. - while (end - ptr >= 8) { - uint64_t data; - memcpy(&data, ptr, 8); - if (data & 0x8080808080808080) goto non_ascii; - ptr += 8; - } +typedef struct { + upb_Message_InternalData* internal; + /* Message data follows. */ +} upb_Message_Internal; - // Check one byte at a time for non-ASCII. - while (ptr < end) { - if (*ptr & 0x80) goto non_ascii; - ptr++; - } +/* Maps upb_CType -> memory size. */ +extern char _upb_CTypeo_size[12]; - return true; +UPB_INLINE size_t upb_msg_sizeof(const upb_MiniTable* l) { + return l->size + sizeof(upb_Message_Internal); +} -non_ascii: - return utf8_range2((const unsigned char*)ptr, end - ptr) == 0; +UPB_INLINE upb_Message* _upb_Message_New_inl(const upb_MiniTable* l, + upb_Arena* a) { + size_t size = upb_msg_sizeof(l); + void* mem = upb_Arena_Malloc(a, size + sizeof(upb_Message_Internal)); + upb_Message* msg; + if (UPB_UNLIKELY(!mem)) return NULL; + msg = UPB_PTR_AT(mem, sizeof(upb_Message_Internal), upb_Message); + memset(mem, 0, size); + return msg; } -const char* decode_checkrequired(upb_Decoder* d, const char* ptr, - const upb_Message* msg, - const upb_MiniTable* l); +/* Creates a new messages with the given layout on the given arena. */ +upb_Message* _upb_Message_New(const upb_MiniTable* l, upb_Arena* a); -/* x86-64 pointers always have the high 16 bits matching. So we can shift - * left 8 and right 8 without loss of information. */ -UPB_INLINE intptr_t decode_totable(const upb_MiniTable* tablep) { - return ((intptr_t)tablep << 8) | tablep->table_mask; +UPB_INLINE upb_Message_Internal* upb_Message_Getinternal(upb_Message* msg) { + ptrdiff_t size = sizeof(upb_Message_Internal); + return (upb_Message_Internal*)((char*)msg - size); } -UPB_INLINE const upb_MiniTable* decode_totablep(intptr_t table) { - return (const upb_MiniTable*)(table >> 8); -} +/* Clears the given message. */ +void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l); -UPB_INLINE -const char* decode_isdonefallback_inl(upb_Decoder* d, const char* ptr, - int overrun, int* status) { - if (overrun < d->limit) { - /* Need to copy remaining data into patch buffer. */ - UPB_ASSERT(overrun < 16); - if (d->unknown_msg) { - if (!_upb_Message_AddUnknown(d->unknown_msg, d->unknown, ptr - d->unknown, - &d->arena)) { - *status = kUpb_DecodeStatus_OutOfMemory; - return NULL; - } - d->unknown = &d->patch[0] + overrun; - } - memset(d->patch + 16, 0, 16); - memcpy(d->patch, d->end, 16); - ptr = &d->patch[0] + overrun; - d->end = &d->patch[16]; - d->limit -= 16; - d->limit_ptr = d->end + d->limit; - d->options &= ~kUpb_DecodeOption_AliasString; - UPB_ASSERT(ptr < d->limit_ptr); - return ptr; - } else { - *status = kUpb_DecodeStatus_Malformed; - return NULL; - } -} +/* Discards the unknown fields for this message only. */ +void _upb_Message_DiscardUnknown_shallow(upb_Message* msg); -const char* decode_isdonefallback(upb_Decoder* d, const char* ptr, int overrun); +/* Adds unknown data (serialized protobuf data) to the given message. The data + * is copied into the message instance. */ +bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, + upb_Arena* arena); -UPB_INLINE -bool decode_isdone(upb_Decoder* d, const char** ptr) { - int overrun = *ptr - d->end; - if (UPB_LIKELY(*ptr < d->limit_ptr)) { - return false; - } else if (UPB_LIKELY(overrun == d->limit)) { - return true; - } else { - *ptr = decode_isdonefallback(d, *ptr, overrun); - return false; - } -} +/** upb_Message_Extension *****************************************************/ -#if UPB_FASTTABLE -UPB_INLINE -const char* fastdecode_tagdispatch(upb_Decoder* d, const char* ptr, - upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t tag) { - const upb_MiniTable* table_p = decode_totablep(table); - uint8_t mask = table; - uint64_t data; - size_t idx = tag & mask; - UPB_ASSUME((idx & 7) == 0); - idx >>= 3; - data = table_p->fasttable[idx].field_data ^ tag; - UPB_MUSTTAIL return table_p->fasttable[idx].field_parser(d, ptr, msg, table, - hasbits, data); +/* The internal representation of an extension is self-describing: it contains + * enough information that we can serialize it to binary format without needing + * to look it up in a upb_ExtensionRegistry. + * + * This representation allocates 16 bytes to data on 64-bit platforms. This is + * rather wasteful for scalars (in the extreme case of bool, it wastes 15 + * bytes). We accept this because we expect messages to be the most common + * extension type. */ +typedef struct { + const upb_MiniTable_Extension* ext; + union { + upb_StringView str; + void* ptr; + char scalar_data[8]; + } data; +} upb_Message_Extension; + +/* Adds the given extension data to the given message. |ext| is copied into the + * message instance. This logically replaces any previously-added extension with + * this number */ +upb_Message_Extension* _upb_Message_GetOrCreateExtension( + upb_Message* msg, const upb_MiniTable_Extension* ext, upb_Arena* arena); + +/* Returns an array of extensions for this message. Note: the array is + * ordered in reverse relative to the order of creation. */ +const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg, + size_t* count); + +/* Returns an extension for the given field number, or NULL if no extension + * exists for this field number. */ +const upb_Message_Extension* _upb_Message_Getext( + const upb_Message* msg, const upb_MiniTable_Extension* ext); + +void _upb_Message_Clearext(upb_Message* msg, + const upb_MiniTable_Extension* ext); + +void _upb_Message_Clearext(upb_Message* msg, + const upb_MiniTable_Extension* ext); + +/** Hasbit access *************************************************************/ + +UPB_INLINE bool _upb_hasbit(const upb_Message* msg, size_t idx) { + return (*UPB_PTR_AT(msg, idx / 8, const char) & (1 << (idx % 8))) != 0; } -#endif -UPB_INLINE uint32_t fastdecode_loadtag(const char* ptr) { - uint16_t tag; - memcpy(&tag, ptr, 2); - return tag; +UPB_INLINE void _upb_sethas(const upb_Message* msg, size_t idx) { + (*UPB_PTR_AT(msg, idx / 8, char)) |= (char)(1 << (idx % 8)); } -UPB_INLINE void decode_checklimit(upb_Decoder* d) { - UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); +UPB_INLINE void _upb_clearhas(const upb_Message* msg, size_t idx) { + (*UPB_PTR_AT(msg, idx / 8, char)) &= (char)(~(1 << (idx % 8))); } -UPB_INLINE int decode_pushlimit(upb_Decoder* d, const char* ptr, int size) { - int limit = size + (int)(ptr - d->end); - int delta = d->limit - limit; - decode_checklimit(d); - d->limit = limit; - d->limit_ptr = d->end + UPB_MIN(0, limit); - decode_checklimit(d); - return delta; +UPB_INLINE size_t _upb_Message_Hasidx(const upb_MiniTable_Field* f) { + UPB_ASSERT(f->presence > 0); + return f->presence; } -UPB_INLINE void decode_poplimit(upb_Decoder* d, const char* ptr, - int saved_delta) { - UPB_ASSERT(ptr - d->end == d->limit); - decode_checklimit(d); - d->limit += saved_delta; - d->limit_ptr = d->end + UPB_MIN(0, d->limit); - decode_checklimit(d); +UPB_INLINE bool _upb_hasbit_field(const upb_Message* msg, + const upb_MiniTable_Field* f) { + return _upb_hasbit(msg, _upb_Message_Hasidx(f)); } +UPB_INLINE void _upb_sethas_field(const upb_Message* msg, + const upb_MiniTable_Field* f) { + _upb_sethas(msg, _upb_Message_Hasidx(f)); +} -#endif /* UPB_DECODE_INT_H_ */ +UPB_INLINE void _upb_clearhas_field(const upb_Message* msg, + const upb_MiniTable_Field* f) { + _upb_clearhas(msg, _upb_Message_Hasidx(f)); +} -/** upb/encode.h ************************************************************/ -/* - * upb_Encode: parsing into a upb_Message using a upb_MiniTable. - */ +/** Oneof case access *********************************************************/ -#ifndef UPB_ENCODE_H_ -#define UPB_ENCODE_H_ +UPB_INLINE uint32_t* _upb_oneofcase(upb_Message* msg, size_t case_ofs) { + return UPB_PTR_AT(msg, case_ofs, uint32_t); +} +UPB_INLINE uint32_t _upb_getoneofcase(const void* msg, size_t case_ofs) { + return *UPB_PTR_AT(msg, case_ofs, uint32_t); +} -/* Must be last. */ +UPB_INLINE size_t _upb_oneofcase_ofs(const upb_MiniTable_Field* f) { + UPB_ASSERT(f->presence < 0); + return ~(ptrdiff_t)f->presence; +} -#ifdef __cplusplus -extern "C" { -#endif +UPB_INLINE uint32_t* _upb_oneofcase_field(upb_Message* msg, + const upb_MiniTable_Field* f) { + return _upb_oneofcase(msg, _upb_oneofcase_ofs(f)); +} -enum { - /* If set, the results of serializing will be deterministic across all - * instances of this binary. There are no guarantees across different - * binary builds. - * - * If your proto contains maps, the encoder will need to malloc()/free() - * memory during encode. */ - kUpb_Encode_Deterministic = 1, +UPB_INLINE uint32_t _upb_getoneofcase_field(const upb_Message* msg, + const upb_MiniTable_Field* f) { + return _upb_getoneofcase(msg, _upb_oneofcase_ofs(f)); +} - /* When set, unknown fields are not printed. */ - kUpb_Encode_SkipUnknown = 2, +UPB_INLINE bool _upb_has_submsg_nohasbit(const upb_Message* msg, size_t ofs) { + return *UPB_PTR_AT(msg, ofs, const upb_Message*) != NULL; +} - /* When set, the encode will fail if any required fields are missing. */ - kUpb_Encode_CheckRequired = 4, -}; +/** upb_Map *******************************************************************/ -#define UPB_ENCODE_MAXDEPTH(depth) ((depth) << 16) +/* Right now we use strmaps for everything. We'll likely want to use + * integer-specific maps for integer-keyed maps.*/ +struct upb_Map { + /* Size of key and val, based on the map type. Strings are represented as '0' + * because they must be handled specially. */ + char key_size; + char val_size; -char* upb_Encode(const void* msg, const upb_MiniTable* l, int options, - upb_Arena* arena, size_t* size); + upb_strtable table; +}; +/* Map entries aren't actually stored, they are only used during parsing. For + * parsing, it helps a lot if all map entry messages have the same layout. + * The compiler and def.c must ensure that all map entries have this layout. */ +typedef struct { + upb_Message_Internal internal; + union { + upb_StringView str; /* For str/bytes. */ + upb_value val; /* For all other types. */ + } k; + union { + upb_StringView str; /* For str/bytes. */ + upb_value val; /* For all other types. */ + } v; +} upb_MapEntry; -#ifdef __cplusplus -} /* extern "C" */ -#endif +/* Creates a new map on the given arena with this key/value type. */ +upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size); -#endif /* UPB_ENCODE_H_ */ +/* Converting between internal table representation and user values. + * + * _upb_map_tokey() and _upb_map_fromkey() are inverses. + * _upb_map_tovalue() and _upb_map_fromvalue() are inverses. + * + * These functions account for the fact that strings are treated differently + * from other types when stored in a map. + */ -/** upb/decode_fast.h ************************************************************/ -// These are the specialized field parser functions for the fast parser. -// Generated tables will refer to these by name. -// -// The function names are encoded with names like: -// -// // 123 4 -// upb_pss_1bt(); // Parse singular string, 1 byte tag. -// -// In position 1: -// - 'p' for parse, most function use this -// - 'c' for copy, for when we are copying strings instead of aliasing -// -// In position 2 (cardinality): -// - 's' for singular, with or without hasbit -// - 'o' for oneof -// - 'r' for non-packed repeated -// - 'p' for packed repeated -// -// In position 3 (type): -// - 'b1' for bool -// - 'v4' for 4-byte varint -// - 'v8' for 8-byte varint -// - 'z4' for zig-zag-encoded 4-byte varint -// - 'z8' for zig-zag-encoded 8-byte varint -// - 'f4' for 4-byte fixed -// - 'f8' for 8-byte fixed -// - 'm' for sub-message -// - 's' for string (validate UTF-8) -// - 'b' for bytes -// -// In position 4 (tag length): -// - '1' for one-byte tags (field numbers 1-15) -// - '2' for two-byte tags (field numbers 16-2048) +UPB_INLINE upb_StringView _upb_map_tokey(const void* key, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + return *(upb_StringView*)key; + } else { + return upb_StringView_FromDataAndSize((const char*)key, size); + } +} -#ifndef UPB_DECODE_FAST_H_ -#define UPB_DECODE_FAST_H_ +UPB_INLINE void _upb_map_fromkey(upb_StringView key, void* out, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + memcpy(out, &key, sizeof(key)); + } else { + memcpy(out, key.data, size); + } +} +UPB_INLINE bool _upb_map_tovalue(const void* val, size_t size, + upb_value* msgval, upb_Arena* a) { + if (size == UPB_MAPTYPE_STRING) { + upb_StringView* strp = (upb_StringView*)upb_Arena_Malloc(a, sizeof(*strp)); + if (!strp) return false; + *strp = *(upb_StringView*)val; + *msgval = upb_value_ptr(strp); + } else { + memcpy(msgval, val, size); + } + return true; +} -struct upb_Decoder; +UPB_INLINE void _upb_map_fromvalue(upb_value val, void* out, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + const upb_StringView* strp = (const upb_StringView*)upb_value_getptr(val); + memcpy(out, strp, sizeof(upb_StringView)); + } else { + memcpy(out, &val, size); + } +} -// The fallback, generic parsing function that can handle any field type. -// This just uses the regular (non-fast) parser to parse a single field. -const char* fastdecode_generic(struct upb_Decoder* d, const char* ptr, - upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t data); +/* Map operations, shared by reflection and generated code. */ -#define UPB_PARSE_PARAMS \ - struct upb_Decoder *d, const char *ptr, upb_Message *msg, intptr_t table, \ - uint64_t hasbits, uint64_t data +UPB_INLINE size_t _upb_Map_Size(const upb_Map* map) { + return map->table.t.count; +} -/* primitive fields ***********************************************************/ +UPB_INLINE bool _upb_Map_Get(const upb_Map* map, const void* key, + size_t key_size, void* val, size_t val_size) { + upb_value tabval; + upb_StringView k = _upb_map_tokey(key, key_size); + bool ret = upb_strtable_lookup2(&map->table, k.data, k.size, &tabval); + if (ret && val) { + _upb_map_fromvalue(tabval, val, val_size); + } + return ret; +} -#define F(card, type, valbytes, tagbytes) \ - const char* upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS); +UPB_INLINE void* _upb_map_next(const upb_Map* map, size_t* iter) { + upb_strtable_iter it; + it.t = &map->table; + it.index = *iter; + upb_strtable_next(&it); + *iter = it.index; + if (upb_strtable_done(&it)) return NULL; + return (void*)str_tabent(&it); +} -#define TYPES(card, tagbytes) \ - F(card, b, 1, tagbytes) \ - F(card, v, 4, tagbytes) \ - F(card, v, 8, tagbytes) \ - F(card, z, 4, tagbytes) \ - F(card, z, 8, tagbytes) \ - F(card, f, 4, tagbytes) \ - F(card, f, 8, tagbytes) +typedef enum { + // LINT.IfChange + _kUpb_MapInsertStatus_Inserted = 0, + _kUpb_MapInsertStatus_Replaced = 1, + _kUpb_MapInsertStatus_OutOfMemory = 2, + // LINT.ThenChange(//depot/google3/third_party/upb/upb/map.h) +} _upb_MapInsertStatus; + +UPB_INLINE _upb_MapInsertStatus _upb_Map_Insert(upb_Map* map, const void* key, + size_t key_size, void* val, + size_t val_size, upb_Arena* a) { + upb_StringView strkey = _upb_map_tokey(key, key_size); + upb_value tabval = {0}; + if (!_upb_map_tovalue(val, val_size, &tabval, a)) { + return _kUpb_MapInsertStatus_OutOfMemory; + } -#define TAGBYTES(card) \ - TYPES(card, 1) \ - TYPES(card, 2) + /* TODO(haberman): add overwrite operation to minimize number of lookups. */ + bool removed = + upb_strtable_remove2(&map->table, strkey.data, strkey.size, NULL); + if (!upb_strtable_insert(&map->table, strkey.data, strkey.size, tabval, a)) { + return _kUpb_MapInsertStatus_OutOfMemory; + } + return removed ? _kUpb_MapInsertStatus_Replaced + : _kUpb_MapInsertStatus_Inserted; +} -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) -TAGBYTES(p) +UPB_INLINE bool _upb_Map_Delete(upb_Map* map, const void* key, + size_t key_size) { + upb_StringView k = _upb_map_tokey(key, key_size); + return upb_strtable_remove2(&map->table, k.data, k.size, NULL); +} -#undef F -#undef TYPES -#undef TAGBYTES +UPB_INLINE void _upb_Map_Clear(upb_Map* map) { + upb_strtable_clear(&map->table); +} -/* string fields **************************************************************/ +/* Message map operations, these get the map from the message first. */ -#define F(card, tagbytes, type) \ - const char* upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS); \ - const char* upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS); +UPB_INLINE size_t _upb_msg_map_size(const upb_Message* msg, size_t ofs) { + upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); + return map ? _upb_Map_Size(map) : 0; +} -#define UTF8(card, tagbytes) \ - F(card, tagbytes, s) \ - F(card, tagbytes, b) +UPB_INLINE bool _upb_msg_map_get(const upb_Message* msg, size_t ofs, + const void* key, size_t key_size, void* val, + size_t val_size) { + upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); + if (!map) return false; + return _upb_Map_Get(map, key, key_size, val, val_size); +} -#define TAGBYTES(card) \ - UTF8(card, 1) \ - UTF8(card, 2) +UPB_INLINE void* _upb_msg_map_next(const upb_Message* msg, size_t ofs, + size_t* iter) { + upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); + if (!map) return NULL; + return _upb_map_next(map, iter); +} -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) +UPB_INLINE bool _upb_msg_map_set(upb_Message* msg, size_t ofs, const void* key, + size_t key_size, void* val, size_t val_size, + upb_Arena* arena) { + upb_Map** map = UPB_PTR_AT(msg, ofs, upb_Map*); + if (!*map) { + *map = _upb_Map_New(arena, key_size, val_size); + } + return _upb_Map_Insert(*map, key, key_size, val, val_size, arena) != + _kUpb_MapInsertStatus_OutOfMemory; +} -#undef F -#undef TAGBYTES +UPB_INLINE bool _upb_msg_map_delete(upb_Message* msg, size_t ofs, + const void* key, size_t key_size) { + upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); + if (!map) return false; + return _upb_Map_Delete(map, key, key_size); +} -/* sub-message fields *********************************************************/ +UPB_INLINE void _upb_msg_map_clear(upb_Message* msg, size_t ofs) { + upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); + if (!map) return; + _upb_Map_Clear(map); +} -#define F(card, tagbytes, size_ceil, ceil_arg) \ - const char* upb_p##card##m_##tagbytes##bt_max##size_ceil##b(UPB_PARSE_PARAMS); +/* Accessing map key/value from a pointer, used by generated code only. */ -#define SIZES(card, tagbytes) \ - F(card, tagbytes, 64, 64) \ - F(card, tagbytes, 128, 128) \ - F(card, tagbytes, 192, 192) \ - F(card, tagbytes, 256, 256) \ - F(card, tagbytes, max, -1) - -#define TAGBYTES(card) \ - SIZES(card, 1) \ - SIZES(card, 2) +UPB_INLINE void _upb_msg_map_key(const void* msg, void* key, size_t size) { + const upb_tabent* ent = (const upb_tabent*)msg; + uint32_t u32len; + upb_StringView k; + k.data = upb_tabstr(ent->key, &u32len); + k.size = u32len; + _upb_map_fromkey(k, key, size); +} -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) +UPB_INLINE void _upb_msg_map_value(const void* msg, void* val, size_t size) { + const upb_tabent* ent = (const upb_tabent*)msg; + upb_value v = {ent->val.val}; + _upb_map_fromvalue(v, val, size); +} -#undef TAGBYTES -#undef SIZES -#undef F +UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, + size_t size) { + upb_tabent* ent = (upb_tabent*)msg; + /* This is like _upb_map_tovalue() except the entry already exists so we can + * reuse the allocated upb_StringView for string fields. */ + if (size == UPB_MAPTYPE_STRING) { + upb_StringView* strp = (upb_StringView*)(uintptr_t)ent->val.val; + memcpy(strp, val, sizeof(*strp)); + } else { + memcpy(&ent->val.val, val, size); + } +} -#undef UPB_PARSE_PARAMS +#ifdef __cplusplus +} /* extern "C" */ +#endif -#endif /* UPB_DECODE_FAST_H_ */ -/** google/protobuf/descriptor.upb.h ************************************************************//* This file was generated by upbc (the upb compiler) from the input +#endif /* UPB_MSG_INT_H_ */ +/* This file was generated by upbc (the upb compiler) from the input * file: * * google/protobuf/descriptor.proto @@ -2314,296 +2181,593 @@ TAGBYTES(r) #define GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ +/* + * upb_decode: parsing into a upb_Message using a upb_MiniTable. + */ + +#ifndef UPB_DECODE_H_ +#define UPB_DECODE_H_ + + +// Must be last. #ifdef __cplusplus extern "C" { #endif -struct google_protobuf_FileDescriptorSet; -struct google_protobuf_FileDescriptorProto; -struct google_protobuf_DescriptorProto; -struct google_protobuf_DescriptorProto_ExtensionRange; -struct google_protobuf_DescriptorProto_ReservedRange; -struct google_protobuf_ExtensionRangeOptions; -struct google_protobuf_FieldDescriptorProto; -struct google_protobuf_OneofDescriptorProto; -struct google_protobuf_EnumDescriptorProto; -struct google_protobuf_EnumDescriptorProto_EnumReservedRange; -struct google_protobuf_EnumValueDescriptorProto; -struct google_protobuf_ServiceDescriptorProto; -struct google_protobuf_MethodDescriptorProto; -struct google_protobuf_FileOptions; -struct google_protobuf_MessageOptions; -struct google_protobuf_FieldOptions; -struct google_protobuf_OneofOptions; -struct google_protobuf_EnumOptions; -struct google_protobuf_EnumValueOptions; -struct google_protobuf_ServiceOptions; -struct google_protobuf_MethodOptions; -struct google_protobuf_UninterpretedOption; -struct google_protobuf_UninterpretedOption_NamePart; -struct google_protobuf_SourceCodeInfo; -struct google_protobuf_SourceCodeInfo_Location; -struct google_protobuf_GeneratedCodeInfo; -struct google_protobuf_GeneratedCodeInfo_Annotation; -typedef struct google_protobuf_FileDescriptorSet google_protobuf_FileDescriptorSet; -typedef struct google_protobuf_FileDescriptorProto google_protobuf_FileDescriptorProto; -typedef struct google_protobuf_DescriptorProto google_protobuf_DescriptorProto; -typedef struct google_protobuf_DescriptorProto_ExtensionRange google_protobuf_DescriptorProto_ExtensionRange; -typedef struct google_protobuf_DescriptorProto_ReservedRange google_protobuf_DescriptorProto_ReservedRange; -typedef struct google_protobuf_ExtensionRangeOptions google_protobuf_ExtensionRangeOptions; -typedef struct google_protobuf_FieldDescriptorProto google_protobuf_FieldDescriptorProto; -typedef struct google_protobuf_OneofDescriptorProto google_protobuf_OneofDescriptorProto; -typedef struct google_protobuf_EnumDescriptorProto google_protobuf_EnumDescriptorProto; -typedef struct google_protobuf_EnumDescriptorProto_EnumReservedRange google_protobuf_EnumDescriptorProto_EnumReservedRange; -typedef struct google_protobuf_EnumValueDescriptorProto google_protobuf_EnumValueDescriptorProto; -typedef struct google_protobuf_ServiceDescriptorProto google_protobuf_ServiceDescriptorProto; -typedef struct google_protobuf_MethodDescriptorProto google_protobuf_MethodDescriptorProto; -typedef struct google_protobuf_FileOptions google_protobuf_FileOptions; -typedef struct google_protobuf_MessageOptions google_protobuf_MessageOptions; -typedef struct google_protobuf_FieldOptions google_protobuf_FieldOptions; -typedef struct google_protobuf_OneofOptions google_protobuf_OneofOptions; -typedef struct google_protobuf_EnumOptions google_protobuf_EnumOptions; -typedef struct google_protobuf_EnumValueOptions google_protobuf_EnumValueOptions; -typedef struct google_protobuf_ServiceOptions google_protobuf_ServiceOptions; -typedef struct google_protobuf_MethodOptions google_protobuf_MethodOptions; -typedef struct google_protobuf_UninterpretedOption google_protobuf_UninterpretedOption; -typedef struct google_protobuf_UninterpretedOption_NamePart google_protobuf_UninterpretedOption_NamePart; -typedef struct google_protobuf_SourceCodeInfo google_protobuf_SourceCodeInfo; -typedef struct google_protobuf_SourceCodeInfo_Location google_protobuf_SourceCodeInfo_Location; -typedef struct google_protobuf_GeneratedCodeInfo google_protobuf_GeneratedCodeInfo; -typedef struct google_protobuf_GeneratedCodeInfo_Annotation google_protobuf_GeneratedCodeInfo_Annotation; -extern const upb_MiniTable google_protobuf_FileDescriptorSet_msginit; -extern const upb_MiniTable google_protobuf_FileDescriptorProto_msginit; -extern const upb_MiniTable google_protobuf_DescriptorProto_msginit; -extern const upb_MiniTable google_protobuf_DescriptorProto_ExtensionRange_msginit; -extern const upb_MiniTable google_protobuf_DescriptorProto_ReservedRange_msginit; -extern const upb_MiniTable google_protobuf_ExtensionRangeOptions_msginit; -extern const upb_MiniTable google_protobuf_FieldDescriptorProto_msginit; -extern const upb_MiniTable google_protobuf_OneofDescriptorProto_msginit; -extern const upb_MiniTable google_protobuf_EnumDescriptorProto_msginit; -extern const upb_MiniTable google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit; -extern const upb_MiniTable google_protobuf_EnumValueDescriptorProto_msginit; -extern const upb_MiniTable google_protobuf_ServiceDescriptorProto_msginit; -extern const upb_MiniTable google_protobuf_MethodDescriptorProto_msginit; -extern const upb_MiniTable google_protobuf_FileOptions_msginit; -extern const upb_MiniTable google_protobuf_MessageOptions_msginit; -extern const upb_MiniTable google_protobuf_FieldOptions_msginit; -extern const upb_MiniTable google_protobuf_OneofOptions_msginit; -extern const upb_MiniTable google_protobuf_EnumOptions_msginit; -extern const upb_MiniTable google_protobuf_EnumValueOptions_msginit; -extern const upb_MiniTable google_protobuf_ServiceOptions_msginit; -extern const upb_MiniTable google_protobuf_MethodOptions_msginit; -extern const upb_MiniTable google_protobuf_UninterpretedOption_msginit; -extern const upb_MiniTable google_protobuf_UninterpretedOption_NamePart_msginit; -extern const upb_MiniTable google_protobuf_SourceCodeInfo_msginit; -extern const upb_MiniTable google_protobuf_SourceCodeInfo_Location_msginit; -extern const upb_MiniTable google_protobuf_GeneratedCodeInfo_msginit; -extern const upb_MiniTable google_protobuf_GeneratedCodeInfo_Annotation_msginit; +enum { + /* If set, strings will alias the input buffer instead of copying into the + * arena. */ + kUpb_DecodeOption_AliasString = 1, -typedef enum { - google_protobuf_FieldDescriptorProto_LABEL_OPTIONAL = 1, - google_protobuf_FieldDescriptorProto_LABEL_REQUIRED = 2, - google_protobuf_FieldDescriptorProto_LABEL_REPEATED = 3 -} google_protobuf_FieldDescriptorProto_Label; + /* If set, the parse will return failure if any message is missing any + * required fields when the message data ends. The parse will still continue, + * and the failure will only be reported at the end. + * + * IMPORTANT CAVEATS: + * + * 1. This can throw a false positive failure if an incomplete message is seen + * on the wire but is later completed when the sub-message occurs again. + * For this reason, a second pass is required to verify a failure, to be + * truly robust. + * + * 2. This can return a false success if you are decoding into a message that + * already has some sub-message fields present. If the sub-message does + * not occur in the binary payload, we will never visit it and discover the + * incomplete sub-message. For this reason, this check is only useful for + * implemting ParseFromString() semantics. For MergeFromString(), a + * post-parse validation step will always be necessary. */ + kUpb_DecodeOption_CheckRequired = 2, +}; -typedef enum { - google_protobuf_FieldDescriptorProto_TYPE_DOUBLE = 1, - google_protobuf_FieldDescriptorProto_TYPE_FLOAT = 2, - google_protobuf_FieldDescriptorProto_TYPE_INT64 = 3, - google_protobuf_FieldDescriptorProto_TYPE_UINT64 = 4, - google_protobuf_FieldDescriptorProto_TYPE_INT32 = 5, - google_protobuf_FieldDescriptorProto_TYPE_FIXED64 = 6, - google_protobuf_FieldDescriptorProto_TYPE_FIXED32 = 7, - google_protobuf_FieldDescriptorProto_TYPE_BOOL = 8, - google_protobuf_FieldDescriptorProto_TYPE_STRING = 9, - google_protobuf_FieldDescriptorProto_TYPE_GROUP = 10, - google_protobuf_FieldDescriptorProto_TYPE_MESSAGE = 11, - google_protobuf_FieldDescriptorProto_TYPE_BYTES = 12, - google_protobuf_FieldDescriptorProto_TYPE_UINT32 = 13, - google_protobuf_FieldDescriptorProto_TYPE_ENUM = 14, - google_protobuf_FieldDescriptorProto_TYPE_SFIXED32 = 15, - google_protobuf_FieldDescriptorProto_TYPE_SFIXED64 = 16, - google_protobuf_FieldDescriptorProto_TYPE_SINT32 = 17, - google_protobuf_FieldDescriptorProto_TYPE_SINT64 = 18 -} google_protobuf_FieldDescriptorProto_Type; +#define UPB_DECODE_MAXDEPTH(depth) ((depth) << 16) typedef enum { - google_protobuf_FieldOptions_STRING = 0, - google_protobuf_FieldOptions_CORD = 1, - google_protobuf_FieldOptions_STRING_PIECE = 2 -} google_protobuf_FieldOptions_CType; + kUpb_DecodeStatus_Ok = 0, + kUpb_DecodeStatus_Malformed = 1, // Wire format was corrupt + kUpb_DecodeStatus_OutOfMemory = 2, // Arena alloc failed + kUpb_DecodeStatus_BadUtf8 = 3, // String field had bad UTF-8 + kUpb_DecodeStatus_MaxDepthExceeded = 4, // Exceeded UPB_DECODE_MAXDEPTH -typedef enum { - google_protobuf_FieldOptions_JS_NORMAL = 0, - google_protobuf_FieldOptions_JS_STRING = 1, - google_protobuf_FieldOptions_JS_NUMBER = 2 -} google_protobuf_FieldOptions_JSType; + // kUpb_DecodeOption_CheckRequired failed (see above), but the parse otherwise + // succeeded. + kUpb_DecodeStatus_MissingRequired = 5, +} upb_DecodeStatus; -typedef enum { - google_protobuf_FileOptions_SPEED = 1, - google_protobuf_FileOptions_CODE_SIZE = 2, - google_protobuf_FileOptions_LITE_RUNTIME = 3 -} google_protobuf_FileOptions_OptimizeMode; +upb_DecodeStatus upb_Decode(const char* buf, size_t size, upb_Message* msg, + const upb_MiniTable* l, + const upb_ExtensionRegistry* extreg, int options, + upb_Arena* arena); -typedef enum { - google_protobuf_MethodOptions_IDEMPOTENCY_UNKNOWN = 0, - google_protobuf_MethodOptions_NO_SIDE_EFFECTS = 1, - google_protobuf_MethodOptions_IDEMPOTENT = 2 -} google_protobuf_MethodOptions_IdempotencyLevel; +#ifdef __cplusplus +} /* extern "C" */ +#endif -extern const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enuminit; -extern const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enuminit; -extern const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enuminit; -extern const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enuminit; -extern const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enuminit; -extern const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enuminit; +#endif /* UPB_DECODE_H_ */ -/* google.protobuf.FileDescriptorSet */ +// These are the specialized field parser functions for the fast parser. +// Generated tables will refer to these by name. +// +// The function names are encoded with names like: +// +// // 123 4 +// upb_pss_1bt(); // Parse singular string, 1 byte tag. +// +// In position 1: +// - 'p' for parse, most function use this +// - 'c' for copy, for when we are copying strings instead of aliasing +// +// In position 2 (cardinality): +// - 's' for singular, with or without hasbit +// - 'o' for oneof +// - 'r' for non-packed repeated +// - 'p' for packed repeated +// +// In position 3 (type): +// - 'b1' for bool +// - 'v4' for 4-byte varint +// - 'v8' for 8-byte varint +// - 'z4' for zig-zag-encoded 4-byte varint +// - 'z8' for zig-zag-encoded 8-byte varint +// - 'f4' for 4-byte fixed +// - 'f8' for 8-byte fixed +// - 'm' for sub-message +// - 's' for string (validate UTF-8) +// - 'b' for bytes +// +// In position 4 (tag length): +// - '1' for one-byte tags (field numbers 1-15) +// - '2' for two-byte tags (field numbers 16-2048) -UPB_INLINE google_protobuf_FileDescriptorSet* google_protobuf_FileDescriptorSet_new(upb_Arena* arena) { - return (google_protobuf_FileDescriptorSet*)_upb_Message_New(&google_protobuf_FileDescriptorSet_msginit, arena); -} -UPB_INLINE google_protobuf_FileDescriptorSet* google_protobuf_FileDescriptorSet_parse(const char* buf, size_t size, upb_Arena* arena) { - google_protobuf_FileDescriptorSet* ret = google_protobuf_FileDescriptorSet_new(arena); - if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorSet_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { - return NULL; - } - return ret; -} -UPB_INLINE google_protobuf_FileDescriptorSet* google_protobuf_FileDescriptorSet_parse_ex(const char* buf, size_t size, - const upb_ExtensionRegistry* extreg, - int options, upb_Arena* arena) { - google_protobuf_FileDescriptorSet* ret = google_protobuf_FileDescriptorSet_new(arena); - if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorSet_msginit, extreg, options, arena) != - kUpb_DecodeStatus_Ok) { - return NULL; - } - return ret; -} -UPB_INLINE char* google_protobuf_FileDescriptorSet_serialize(const google_protobuf_FileDescriptorSet* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FileDescriptorSet_msginit, 0, arena, len); -} -UPB_INLINE char* google_protobuf_FileDescriptorSet_serialize_ex(const google_protobuf_FileDescriptorSet* msg, int options, - upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FileDescriptorSet_msginit, options, arena, len); -} -UPB_INLINE bool google_protobuf_FileDescriptorSet_has_file(const google_protobuf_FileDescriptorSet* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); -} -UPB_INLINE const google_protobuf_FileDescriptorProto* const* google_protobuf_FileDescriptorSet_file(const google_protobuf_FileDescriptorSet* msg, size_t* len) { - return (const google_protobuf_FileDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); -} +#ifndef UPB_DECODE_FAST_H_ +#define UPB_DECODE_FAST_H_ -UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_mutable_file(google_protobuf_FileDescriptorSet* msg, size_t* len) { - return (google_protobuf_FileDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); -} -UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_resize_file(google_protobuf_FileDescriptorSet* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_FileDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); -} -UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorSet_add_file(google_protobuf_FileDescriptorSet* msg, upb_Arena* arena) { - struct google_protobuf_FileDescriptorProto* sub = (struct google_protobuf_FileDescriptorProto*)_upb_Message_New(&google_protobuf_FileDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); - if (!ok) return NULL; - return sub; -} -/* google.protobuf.FileDescriptorProto */ +// Must be last. -UPB_INLINE google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorProto_new(upb_Arena* arena) { - return (google_protobuf_FileDescriptorProto*)_upb_Message_New(&google_protobuf_FileDescriptorProto_msginit, arena); -} -UPB_INLINE google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { - google_protobuf_FileDescriptorProto* ret = google_protobuf_FileDescriptorProto_new(arena); - if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { - return NULL; - } - return ret; -} -UPB_INLINE google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorProto_parse_ex(const char* buf, size_t size, - const upb_ExtensionRegistry* extreg, - int options, upb_Arena* arena) { - google_protobuf_FileDescriptorProto* ret = google_protobuf_FileDescriptorProto_new(arena); - if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorProto_msginit, extreg, options, arena) != +#ifdef __cplusplus +extern "C" { +#endif + +struct upb_Decoder; + +// The fallback, generic parsing function that can handle any field type. +// This just uses the regular (non-fast) parser to parse a single field. +const char* _upb_FastDecoder_DecodeGeneric(struct upb_Decoder* d, + const char* ptr, upb_Message* msg, + intptr_t table, uint64_t hasbits, + uint64_t data); + +#define UPB_PARSE_PARAMS \ + struct upb_Decoder *d, const char *ptr, upb_Message *msg, intptr_t table, \ + uint64_t hasbits, uint64_t data + +/* primitive fields ***********************************************************/ + +#define F(card, type, valbytes, tagbytes) \ + const char* upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS); + +#define TYPES(card, tagbytes) \ + F(card, b, 1, tagbytes) \ + F(card, v, 4, tagbytes) \ + F(card, v, 8, tagbytes) \ + F(card, z, 4, tagbytes) \ + F(card, z, 8, tagbytes) \ + F(card, f, 4, tagbytes) \ + F(card, f, 8, tagbytes) + +#define TAGBYTES(card) \ + TYPES(card, 1) \ + TYPES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) +TAGBYTES(p) + +#undef F +#undef TYPES +#undef TAGBYTES + +/* string fields **************************************************************/ + +#define F(card, tagbytes, type) \ + const char* upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS); \ + const char* upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS); + +#define UTF8(card, tagbytes) \ + F(card, tagbytes, s) \ + F(card, tagbytes, b) + +#define TAGBYTES(card) \ + UTF8(card, 1) \ + UTF8(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) + +#undef F +#undef TAGBYTES + +/* sub-message fields *********************************************************/ + +#define F(card, tagbytes, size_ceil, ceil_arg) \ + const char* upb_p##card##m_##tagbytes##bt_max##size_ceil##b(UPB_PARSE_PARAMS); + +#define SIZES(card, tagbytes) \ + F(card, tagbytes, 64, 64) \ + F(card, tagbytes, 128, 128) \ + F(card, tagbytes, 192, 192) \ + F(card, tagbytes, 256, 256) \ + F(card, tagbytes, max, -1) + +#define TAGBYTES(card) \ + SIZES(card, 1) \ + SIZES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) + +#undef TAGBYTES +#undef SIZES +#undef F + +#undef UPB_PARSE_PARAMS + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_DECODE_FAST_H_ */ + +/* + * upb_Encode: parsing from a upb_Message using a upb_MiniTable. + */ + +#ifndef UPB_ENCODE_H_ +#define UPB_ENCODE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* If set, the results of serializing will be deterministic across all + * instances of this binary. There are no guarantees across different + * binary builds. + * + * If your proto contains maps, the encoder will need to malloc()/free() + * memory during encode. */ + kUpb_EncodeOption_Deterministic = 1, + + /* When set, unknown fields are not printed. */ + kUpb_EncodeOption_SkipUnknown = 2, + + /* When set, the encode will fail if any required fields are missing. */ + kUpb_EncodeOption_CheckRequired = 4, +}; + +#define UPB_ENCODE_MAXDEPTH(depth) ((depth) << 16) + +typedef enum { + kUpb_EncodeStatus_Ok = 0, + kUpb_EncodeStatus_OutOfMemory = 1, // Arena alloc failed + kUpb_EncodeStatus_MaxDepthExceeded = 2, // Exceeded UPB_ENCODE_MAXDEPTH + + // kUpb_EncodeOption_CheckRequired failed but the parse otherwise succeeded. + kUpb_EncodeStatus_MissingRequired = 3, +} upb_EncodeStatus; + +upb_EncodeStatus upb_Encode(const void* msg, const upb_MiniTable* l, + int options, upb_Arena* arena, char** buf, + size_t* size); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_ENCODE_H_ */ + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct google_protobuf_FileDescriptorSet google_protobuf_FileDescriptorSet; +typedef struct google_protobuf_FileDescriptorProto google_protobuf_FileDescriptorProto; +typedef struct google_protobuf_DescriptorProto google_protobuf_DescriptorProto; +typedef struct google_protobuf_DescriptorProto_ExtensionRange google_protobuf_DescriptorProto_ExtensionRange; +typedef struct google_protobuf_DescriptorProto_ReservedRange google_protobuf_DescriptorProto_ReservedRange; +typedef struct google_protobuf_ExtensionRangeOptions google_protobuf_ExtensionRangeOptions; +typedef struct google_protobuf_FieldDescriptorProto google_protobuf_FieldDescriptorProto; +typedef struct google_protobuf_OneofDescriptorProto google_protobuf_OneofDescriptorProto; +typedef struct google_protobuf_EnumDescriptorProto google_protobuf_EnumDescriptorProto; +typedef struct google_protobuf_EnumDescriptorProto_EnumReservedRange google_protobuf_EnumDescriptorProto_EnumReservedRange; +typedef struct google_protobuf_EnumValueDescriptorProto google_protobuf_EnumValueDescriptorProto; +typedef struct google_protobuf_ServiceDescriptorProto google_protobuf_ServiceDescriptorProto; +typedef struct google_protobuf_MethodDescriptorProto google_protobuf_MethodDescriptorProto; +typedef struct google_protobuf_FileOptions google_protobuf_FileOptions; +typedef struct google_protobuf_MessageOptions google_protobuf_MessageOptions; +typedef struct google_protobuf_FieldOptions google_protobuf_FieldOptions; +typedef struct google_protobuf_OneofOptions google_protobuf_OneofOptions; +typedef struct google_protobuf_EnumOptions google_protobuf_EnumOptions; +typedef struct google_protobuf_EnumValueOptions google_protobuf_EnumValueOptions; +typedef struct google_protobuf_ServiceOptions google_protobuf_ServiceOptions; +typedef struct google_protobuf_MethodOptions google_protobuf_MethodOptions; +typedef struct google_protobuf_UninterpretedOption google_protobuf_UninterpretedOption; +typedef struct google_protobuf_UninterpretedOption_NamePart google_protobuf_UninterpretedOption_NamePart; +typedef struct google_protobuf_SourceCodeInfo google_protobuf_SourceCodeInfo; +typedef struct google_protobuf_SourceCodeInfo_Location google_protobuf_SourceCodeInfo_Location; +typedef struct google_protobuf_GeneratedCodeInfo google_protobuf_GeneratedCodeInfo; +typedef struct google_protobuf_GeneratedCodeInfo_Annotation google_protobuf_GeneratedCodeInfo_Annotation; +extern const upb_MiniTable google_protobuf_FileDescriptorSet_msg_init; +extern const upb_MiniTable google_protobuf_FileDescriptorProto_msg_init; +extern const upb_MiniTable google_protobuf_DescriptorProto_msg_init; +extern const upb_MiniTable google_protobuf_DescriptorProto_ExtensionRange_msg_init; +extern const upb_MiniTable google_protobuf_DescriptorProto_ReservedRange_msg_init; +extern const upb_MiniTable google_protobuf_ExtensionRangeOptions_msg_init; +extern const upb_MiniTable google_protobuf_FieldDescriptorProto_msg_init; +extern const upb_MiniTable google_protobuf_OneofDescriptorProto_msg_init; +extern const upb_MiniTable google_protobuf_EnumDescriptorProto_msg_init; +extern const upb_MiniTable google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init; +extern const upb_MiniTable google_protobuf_EnumValueDescriptorProto_msg_init; +extern const upb_MiniTable google_protobuf_ServiceDescriptorProto_msg_init; +extern const upb_MiniTable google_protobuf_MethodDescriptorProto_msg_init; +extern const upb_MiniTable google_protobuf_FileOptions_msg_init; +extern const upb_MiniTable google_protobuf_MessageOptions_msg_init; +extern const upb_MiniTable google_protobuf_FieldOptions_msg_init; +extern const upb_MiniTable google_protobuf_OneofOptions_msg_init; +extern const upb_MiniTable google_protobuf_EnumOptions_msg_init; +extern const upb_MiniTable google_protobuf_EnumValueOptions_msg_init; +extern const upb_MiniTable google_protobuf_ServiceOptions_msg_init; +extern const upb_MiniTable google_protobuf_MethodOptions_msg_init; +extern const upb_MiniTable google_protobuf_UninterpretedOption_msg_init; +extern const upb_MiniTable google_protobuf_UninterpretedOption_NamePart_msg_init; +extern const upb_MiniTable google_protobuf_SourceCodeInfo_msg_init; +extern const upb_MiniTable google_protobuf_SourceCodeInfo_Location_msg_init; +extern const upb_MiniTable google_protobuf_GeneratedCodeInfo_msg_init; +extern const upb_MiniTable google_protobuf_GeneratedCodeInfo_Annotation_msg_init; + +typedef enum { + google_protobuf_FieldDescriptorProto_LABEL_OPTIONAL = 1, + google_protobuf_FieldDescriptorProto_LABEL_REQUIRED = 2, + google_protobuf_FieldDescriptorProto_LABEL_REPEATED = 3 +} google_protobuf_FieldDescriptorProto_Label; + +typedef enum { + google_protobuf_FieldDescriptorProto_TYPE_DOUBLE = 1, + google_protobuf_FieldDescriptorProto_TYPE_FLOAT = 2, + google_protobuf_FieldDescriptorProto_TYPE_INT64 = 3, + google_protobuf_FieldDescriptorProto_TYPE_UINT64 = 4, + google_protobuf_FieldDescriptorProto_TYPE_INT32 = 5, + google_protobuf_FieldDescriptorProto_TYPE_FIXED64 = 6, + google_protobuf_FieldDescriptorProto_TYPE_FIXED32 = 7, + google_protobuf_FieldDescriptorProto_TYPE_BOOL = 8, + google_protobuf_FieldDescriptorProto_TYPE_STRING = 9, + google_protobuf_FieldDescriptorProto_TYPE_GROUP = 10, + google_protobuf_FieldDescriptorProto_TYPE_MESSAGE = 11, + google_protobuf_FieldDescriptorProto_TYPE_BYTES = 12, + google_protobuf_FieldDescriptorProto_TYPE_UINT32 = 13, + google_protobuf_FieldDescriptorProto_TYPE_ENUM = 14, + google_protobuf_FieldDescriptorProto_TYPE_SFIXED32 = 15, + google_protobuf_FieldDescriptorProto_TYPE_SFIXED64 = 16, + google_protobuf_FieldDescriptorProto_TYPE_SINT32 = 17, + google_protobuf_FieldDescriptorProto_TYPE_SINT64 = 18 +} google_protobuf_FieldDescriptorProto_Type; + +typedef enum { + google_protobuf_FieldOptions_STRING = 0, + google_protobuf_FieldOptions_CORD = 1, + google_protobuf_FieldOptions_STRING_PIECE = 2 +} google_protobuf_FieldOptions_CType; + +typedef enum { + google_protobuf_FieldOptions_JS_NORMAL = 0, + google_protobuf_FieldOptions_JS_STRING = 1, + google_protobuf_FieldOptions_JS_NUMBER = 2 +} google_protobuf_FieldOptions_JSType; + +typedef enum { + google_protobuf_FileOptions_SPEED = 1, + google_protobuf_FileOptions_CODE_SIZE = 2, + google_protobuf_FileOptions_LITE_RUNTIME = 3 +} google_protobuf_FileOptions_OptimizeMode; + +typedef enum { + google_protobuf_GeneratedCodeInfo_Annotation_NONE = 0, + google_protobuf_GeneratedCodeInfo_Annotation_SET = 1, + google_protobuf_GeneratedCodeInfo_Annotation_ALIAS = 2 +} google_protobuf_GeneratedCodeInfo_Annotation_Semantic; + +typedef enum { + google_protobuf_MethodOptions_IDEMPOTENCY_UNKNOWN = 0, + google_protobuf_MethodOptions_NO_SIDE_EFFECTS = 1, + google_protobuf_MethodOptions_IDEMPOTENT = 2 +} google_protobuf_MethodOptions_IdempotencyLevel; + + +extern const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enum_init; +extern const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enum_init; +extern const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enum_init; +extern const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enum_init; +extern const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enum_init; +extern const upb_MiniTable_Enum google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init; +extern const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enum_init; + +/* google.protobuf.FileDescriptorSet */ + +UPB_INLINE google_protobuf_FileDescriptorSet* google_protobuf_FileDescriptorSet_new(upb_Arena* arena) { + return (google_protobuf_FileDescriptorSet*)_upb_Message_New(&google_protobuf_FileDescriptorSet_msg_init, arena); +} +UPB_INLINE google_protobuf_FileDescriptorSet* google_protobuf_FileDescriptorSet_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_FileDescriptorSet* ret = google_protobuf_FileDescriptorSet_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorSet_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FileDescriptorSet* google_protobuf_FileDescriptorSet_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FileDescriptorSet* ret = google_protobuf_FileDescriptorSet_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorSet_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } -UPB_INLINE char* google_protobuf_FileDescriptorProto_serialize(const google_protobuf_FileDescriptorProto* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FileDescriptorProto_msginit, 0, arena, len); +UPB_INLINE char* google_protobuf_FileDescriptorSet_serialize(const google_protobuf_FileDescriptorSet* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FileDescriptorSet_msg_init, 0, arena, &ptr, len); + return ptr; } -UPB_INLINE char* google_protobuf_FileDescriptorProto_serialize_ex(const google_protobuf_FileDescriptorProto* msg, int options, +UPB_INLINE char* google_protobuf_FileDescriptorSet_serialize_ex(const google_protobuf_FileDescriptorSet* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FileDescriptorProto_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FileDescriptorSet_msg_init, options, arena, &ptr, len); + return ptr; } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_name(const google_protobuf_FileDescriptorProto* msg) { - return _upb_hasbit(msg, 1); +UPB_INLINE bool google_protobuf_FileDescriptorSet_has_file(const google_protobuf_FileDescriptorSet* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_name(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); +UPB_INLINE void google_protobuf_FileDescriptorSet_clear_file(const google_protobuf_FileDescriptorSet* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_package(const google_protobuf_FileDescriptorProto* msg) { - return _upb_hasbit(msg, 2); +UPB_INLINE const google_protobuf_FileDescriptorProto* const* google_protobuf_FileDescriptorSet_file(const google_protobuf_FileDescriptorSet* msg, size_t* len) { + return (const google_protobuf_FileDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_package(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); + +UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_mutable_file(google_protobuf_FileDescriptorSet* msg, size_t* len) { + return (google_protobuf_FileDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); +} +UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_resize_file(google_protobuf_FileDescriptorSet* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_FileDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); +} +UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorSet_add_file(google_protobuf_FileDescriptorSet* msg, upb_Arena* arena) { + struct google_protobuf_FileDescriptorProto* sub = (struct google_protobuf_FileDescriptorProto*)_upb_Message_New(&google_protobuf_FileDescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); + if (!ok) return NULL; + return sub; +} + +/* google.protobuf.FileDescriptorProto */ + +UPB_INLINE google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorProto_new(upb_Arena* arena) { + return (google_protobuf_FileDescriptorProto*)_upb_Message_New(&google_protobuf_FileDescriptorProto_msg_init, arena); +} +UPB_INLINE google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_FileDescriptorProto* ret = google_protobuf_FileDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorProto_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorProto_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FileDescriptorProto* ret = google_protobuf_FileDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorProto_msg_init, extreg, options, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FileDescriptorProto_serialize(const google_protobuf_FileDescriptorProto* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FileDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FileDescriptorProto_serialize_ex(const google_protobuf_FileDescriptorProto* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FileDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_name(const google_protobuf_FileDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_name(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} +UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_name(const google_protobuf_FileDescriptorProto* msg) { + return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_package(const google_protobuf_FileDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_package(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); +} +UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_package(const google_protobuf_FileDescriptorProto* msg) { + return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_dependency(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(20, 40)); } UPB_INLINE upb_StringView const* google_protobuf_FileDescriptorProto_dependency(const google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); + return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_message_type(const google_protobuf_FileDescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_message_type(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(24, 48)); } UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_FileDescriptorProto_message_type(const google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); + return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_enum_type(const google_protobuf_FileDescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(44, 88)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 56)); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_enum_type(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(28, 56)); } UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_FileDescriptorProto_enum_type(const google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); + return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_service(const google_protobuf_FileDescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(48, 96)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(32, 64)); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_service(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(32, 64)); } UPB_INLINE const google_protobuf_ServiceDescriptorProto* const* google_protobuf_FileDescriptorProto_service(const google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (const google_protobuf_ServiceDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(48, 96), len); + return (const google_protobuf_ServiceDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(32, 64), len); } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_extension(const google_protobuf_FileDescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(52, 104)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(36, 72)); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_extension(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(36, 72)); } UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_FileDescriptorProto_extension(const google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(52, 104), len); + return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_options(const google_protobuf_FileDescriptorProto* msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_options(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(40, 80), const upb_Message*) = NULL; + _upb_clearhas(msg, 3); +} UPB_INLINE const google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_options(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const google_protobuf_FileOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(40, 80), const google_protobuf_FileOptions*); } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_source_code_info(const google_protobuf_FileDescriptorProto* msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_source_code_info(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(44, 88), const upb_Message*) = NULL; + _upb_clearhas(msg, 4); +} UPB_INLINE const google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_source_code_info(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(32, 64), const google_protobuf_SourceCodeInfo*); + return *UPB_PTR_AT(msg, UPB_SIZE(44, 88), const google_protobuf_SourceCodeInfo*); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_public_dependency(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(48, 96)); } UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_public_dependency(const google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(56, 112), len); + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(48, 96), len); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_weak_dependency(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(52, 104)); } UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_weak_dependency(const google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(60, 120), len); + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(52, 104), len); } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_syntax(const google_protobuf_FileDescriptorProto* msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_syntax(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(56, 112), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 5); +} UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_syntax(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(56, 112), upb_StringView); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_edition(const google_protobuf_FileDescriptorProto* msg) { + return _upb_hasbit(msg, 6); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_edition(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(64, 128), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 6); +} +UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_edition(const google_protobuf_FileDescriptorProto* msg) { + return *UPB_PTR_AT(msg, UPB_SIZE(64, 128), upb_StringView); } UPB_INLINE void google_protobuf_FileDescriptorProto_set_name(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { @@ -2615,70 +2779,70 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_set_package(google_protobuf_ *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = value; } UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_mutable_dependency(google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len); + return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); } UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_resize_dependency(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { - return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(3, 4), arena); + return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(3, 4), arena); } UPB_INLINE bool google_protobuf_FileDescriptorProto_add_dependency(google_protobuf_FileDescriptorProto* msg, upb_StringView val, upb_Arena* arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(36, 72), UPB_SIZE(3, 4), &val, arena); + return _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), UPB_SIZE(3, 4), &val, arena); } UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_mutable_message_type(google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(40, 80), len); + return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); } UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_resize_message_type(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(40, 80), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_FileDescriptorProto_add_message_type(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { - struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(40, 80), UPB_SIZE(2, 3), &sub, arena); + struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_mutable_enum_type(google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(44, 88), len); + return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); } UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_resize_enum_type(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(44, 88), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_FileDescriptorProto_add_enum_type(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { - struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(44, 88), UPB_SIZE(2, 3), &sub, arena); + struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_mutable_service(google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (google_protobuf_ServiceDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(48, 96), len); + return (google_protobuf_ServiceDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 64), len); } UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_resize_service(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_ServiceDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(48, 96), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_ServiceDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(32, 64), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_ServiceDescriptorProto* google_protobuf_FileDescriptorProto_add_service(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { - struct google_protobuf_ServiceDescriptorProto* sub = (struct google_protobuf_ServiceDescriptorProto*)_upb_Message_New(&google_protobuf_ServiceDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(48, 96), UPB_SIZE(2, 3), &sub, arena); + struct google_protobuf_ServiceDescriptorProto* sub = (struct google_protobuf_ServiceDescriptorProto*)_upb_Message_New(&google_protobuf_ServiceDescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(32, 64), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_mutable_extension(google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(52, 104), len); + return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len); } UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_resize_extension(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(52, 104), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_FileDescriptorProto_add_extension(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { - struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(52, 104), UPB_SIZE(2, 3), &sub, arena); + struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(36, 72), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_FileDescriptorProto_set_options(google_protobuf_FileDescriptorProto *msg, google_protobuf_FileOptions* value) { _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(28, 56), google_protobuf_FileOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(40, 80), google_protobuf_FileOptions*) = value; } UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_mutable_options(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_FileOptions* sub = (struct google_protobuf_FileOptions*)google_protobuf_FileDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_FileOptions*)_upb_Message_New(&google_protobuf_FileOptions_msginit, arena); + sub = (struct google_protobuf_FileOptions*)_upb_Message_New(&google_protobuf_FileOptions_msg_init, arena); if (!sub) return NULL; google_protobuf_FileDescriptorProto_set_options(msg, sub); } @@ -2686,49 +2850,53 @@ UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorPro } UPB_INLINE void google_protobuf_FileDescriptorProto_set_source_code_info(google_protobuf_FileDescriptorProto *msg, google_protobuf_SourceCodeInfo* value) { _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(32, 64), google_protobuf_SourceCodeInfo*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(44, 88), google_protobuf_SourceCodeInfo*) = value; } UPB_INLINE struct google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_mutable_source_code_info(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_SourceCodeInfo* sub = (struct google_protobuf_SourceCodeInfo*)google_protobuf_FileDescriptorProto_source_code_info(msg); if (sub == NULL) { - sub = (struct google_protobuf_SourceCodeInfo*)_upb_Message_New(&google_protobuf_SourceCodeInfo_msginit, arena); + sub = (struct google_protobuf_SourceCodeInfo*)_upb_Message_New(&google_protobuf_SourceCodeInfo_msg_init, arena); if (!sub) return NULL; google_protobuf_FileDescriptorProto_set_source_code_info(msg, sub); } return sub; } UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_public_dependency(google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(56, 112), len); + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(48, 96), len); } UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_public_dependency(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(56, 112), len, 2, arena); + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(48, 96), len, 2, arena); } UPB_INLINE bool google_protobuf_FileDescriptorProto_add_public_dependency(google_protobuf_FileDescriptorProto* msg, int32_t val, upb_Arena* arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(56, 112), 2, &val, arena); + return _upb_Array_Append_accessor2(msg, UPB_SIZE(48, 96), 2, &val, arena); } UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_weak_dependency(google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(60, 120), len); + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(52, 104), len); } UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_weak_dependency(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(60, 120), len, 2, arena); + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(52, 104), len, 2, arena); } UPB_INLINE bool google_protobuf_FileDescriptorProto_add_weak_dependency(google_protobuf_FileDescriptorProto* msg, int32_t val, upb_Arena* arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(60, 120), 2, &val, arena); + return _upb_Array_Append_accessor2(msg, UPB_SIZE(52, 104), 2, &val, arena); } UPB_INLINE void google_protobuf_FileDescriptorProto_set_syntax(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(56, 112), upb_StringView) = value; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_edition(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { + _upb_sethas(msg, 6); + *UPB_PTR_AT(msg, UPB_SIZE(64, 128), upb_StringView) = value; } /* google.protobuf.DescriptorProto */ UPB_INLINE google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_new(upb_Arena* arena) { - return (google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msginit, arena); + return (google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msg_init, arena); } UPB_INLINE google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_DescriptorProto* ret = google_protobuf_DescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -2738,73 +2906,109 @@ UPB_INLINE google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_pars int options, upb_Arena* arena) { google_protobuf_DescriptorProto* ret = google_protobuf_DescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_DescriptorProto_serialize(const google_protobuf_DescriptorProto* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_DescriptorProto_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_DescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_DescriptorProto_serialize_ex(const google_protobuf_DescriptorProto* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_DescriptorProto_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_DescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_DescriptorProto_has_name(const google_protobuf_DescriptorProto* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_DescriptorProto_clear_name(const google_protobuf_DescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_DescriptorProto_name(const google_protobuf_DescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } UPB_INLINE bool google_protobuf_DescriptorProto_has_field(const google_protobuf_DescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 24)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_field(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(12, 24)); } UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_field(const google_protobuf_DescriptorProto* msg, size_t* len) { - return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); + return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(12, 24), len); } UPB_INLINE bool google_protobuf_DescriptorProto_has_nested_type(const google_protobuf_DescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_nested_type(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(16, 32)); } UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_DescriptorProto_nested_type(const google_protobuf_DescriptorProto* msg, size_t* len) { - return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); + return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); } UPB_INLINE bool google_protobuf_DescriptorProto_has_enum_type(const google_protobuf_DescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_enum_type(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(20, 40)); } UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_DescriptorProto_enum_type(const google_protobuf_DescriptorProto* msg, size_t* len) { - return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); + return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); } UPB_INLINE bool google_protobuf_DescriptorProto_has_extension_range(const google_protobuf_DescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 56)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_extension_range(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(24, 48)); } UPB_INLINE const google_protobuf_DescriptorProto_ExtensionRange* const* google_protobuf_DescriptorProto_extension_range(const google_protobuf_DescriptorProto* msg, size_t* len) { - return (const google_protobuf_DescriptorProto_ExtensionRange* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); + return (const google_protobuf_DescriptorProto_ExtensionRange* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } UPB_INLINE bool google_protobuf_DescriptorProto_has_extension(const google_protobuf_DescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(32, 64)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 56)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_extension(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(28, 56)); } UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_extension(const google_protobuf_DescriptorProto* msg, size_t* len) { - return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(32, 64), len); + return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); } UPB_INLINE bool google_protobuf_DescriptorProto_has_options(const google_protobuf_DescriptorProto* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_DescriptorProto_clear_options(const google_protobuf_DescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(32, 64), const upb_Message*) = NULL; + _upb_clearhas(msg, 2); +} UPB_INLINE const google_protobuf_MessageOptions* google_protobuf_DescriptorProto_options(const google_protobuf_DescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_MessageOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(32, 64), const google_protobuf_MessageOptions*); } UPB_INLINE bool google_protobuf_DescriptorProto_has_oneof_decl(const google_protobuf_DescriptorProto* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(36, 72)); } +UPB_INLINE void google_protobuf_DescriptorProto_clear_oneof_decl(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(36, 72)); +} UPB_INLINE const google_protobuf_OneofDescriptorProto* const* google_protobuf_DescriptorProto_oneof_decl(const google_protobuf_DescriptorProto* msg, size_t* len) { return (const google_protobuf_OneofDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); } UPB_INLINE bool google_protobuf_DescriptorProto_has_reserved_range(const google_protobuf_DescriptorProto* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); } +UPB_INLINE void google_protobuf_DescriptorProto_clear_reserved_range(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(40, 80)); +} UPB_INLINE const google_protobuf_DescriptorProto_ReservedRange* const* google_protobuf_DescriptorProto_reserved_range(const google_protobuf_DescriptorProto* msg, size_t* len) { return (const google_protobuf_DescriptorProto_ReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); } +UPB_INLINE void google_protobuf_DescriptorProto_clear_reserved_name(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(44, 88)); +} UPB_INLINE upb_StringView const* google_protobuf_DescriptorProto_reserved_name(const google_protobuf_DescriptorProto* msg, size_t* len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); } @@ -2814,73 +3018,73 @@ UPB_INLINE void google_protobuf_DescriptorProto_set_name(google_protobuf_Descrip *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; } UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_field(google_protobuf_DescriptorProto* msg, size_t* len) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); + return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 24), len); } UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_field(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 24), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_field(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { - struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); + struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(12, 24), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_mutable_nested_type(google_protobuf_DescriptorProto* msg, size_t* len) { - return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); + return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); } UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_resize_nested_type(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_add_nested_type(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { - struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena); + struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_mutable_enum_type(google_protobuf_DescriptorProto* msg, size_t* len) { - return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); + return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); } UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_resize_enum_type(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_DescriptorProto_add_enum_type(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { - struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena); + struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_mutable_extension_range(google_protobuf_DescriptorProto* msg, size_t* len) { - return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); + return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); } UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_resize_extension_range(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_add_extension_range(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { - struct google_protobuf_DescriptorProto_ExtensionRange* sub = (struct google_protobuf_DescriptorProto_ExtensionRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ExtensionRange_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena); + struct google_protobuf_DescriptorProto_ExtensionRange* sub = (struct google_protobuf_DescriptorProto_ExtensionRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ExtensionRange_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_extension(google_protobuf_DescriptorProto* msg, size_t* len) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 64), len); + return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); } UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_extension(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(32, 64), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_extension(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { - struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(32, 64), UPB_SIZE(2, 3), &sub, arena); + struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_DescriptorProto_set_options(google_protobuf_DescriptorProto *msg, google_protobuf_MessageOptions* value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_MessageOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(32, 64), google_protobuf_MessageOptions*) = value; } UPB_INLINE struct google_protobuf_MessageOptions* google_protobuf_DescriptorProto_mutable_options(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_MessageOptions* sub = (struct google_protobuf_MessageOptions*)google_protobuf_DescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_MessageOptions*)_upb_Message_New(&google_protobuf_MessageOptions_msginit, arena); + sub = (struct google_protobuf_MessageOptions*)_upb_Message_New(&google_protobuf_MessageOptions_msg_init, arena); if (!sub) return NULL; google_protobuf_DescriptorProto_set_options(msg, sub); } @@ -2893,7 +3097,7 @@ UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProt return (google_protobuf_OneofDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_OneofDescriptorProto* google_protobuf_DescriptorProto_add_oneof_decl(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { - struct google_protobuf_OneofDescriptorProto* sub = (struct google_protobuf_OneofDescriptorProto*)_upb_Message_New(&google_protobuf_OneofDescriptorProto_msginit, arena); + struct google_protobuf_OneofDescriptorProto* sub = (struct google_protobuf_OneofDescriptorProto*)_upb_Message_New(&google_protobuf_OneofDescriptorProto_msg_init, arena); bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(36, 72), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; @@ -2905,7 +3109,7 @@ UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_Descr return (google_protobuf_DescriptorProto_ReservedRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(40, 80), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_add_reserved_range(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { - struct google_protobuf_DescriptorProto_ReservedRange* sub = (struct google_protobuf_DescriptorProto_ReservedRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ReservedRange_msginit, arena); + struct google_protobuf_DescriptorProto_ReservedRange* sub = (struct google_protobuf_DescriptorProto_ReservedRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ReservedRange_msg_init, arena); bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(40, 80), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; @@ -2923,12 +3127,12 @@ UPB_INLINE bool google_protobuf_DescriptorProto_add_reserved_name(google_protobu /* google.protobuf.DescriptorProto.ExtensionRange */ UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_ExtensionRange_new(upb_Arena* arena) { - return (google_protobuf_DescriptorProto_ExtensionRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ExtensionRange_msginit, arena); + return (google_protobuf_DescriptorProto_ExtensionRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ExtensionRange_msg_init, arena); } UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_ExtensionRange_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_DescriptorProto_ExtensionRange* ret = google_protobuf_DescriptorProto_ExtensionRange_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ExtensionRange_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ExtensionRange_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -2938,34 +3142,50 @@ UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_Descr int options, upb_Arena* arena) { google_protobuf_DescriptorProto_ExtensionRange* ret = google_protobuf_DescriptorProto_ExtensionRange_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ExtensionRange_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ExtensionRange_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_DescriptorProto_ExtensionRange_serialize(const google_protobuf_DescriptorProto_ExtensionRange* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_DescriptorProto_ExtensionRange_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_DescriptorProto_ExtensionRange_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_DescriptorProto_ExtensionRange_serialize_ex(const google_protobuf_DescriptorProto_ExtensionRange* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_DescriptorProto_ExtensionRange_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_DescriptorProto_ExtensionRange_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_start(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_start(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_start(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_end(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_end(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_end(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 16), const upb_Message*) = NULL; + _upb_clearhas(msg, 3); +} UPB_INLINE const google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 16), const google_protobuf_ExtensionRangeOptions*); } @@ -2985,7 +3205,7 @@ UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_options(googl UPB_INLINE struct google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_mutable_options(google_protobuf_DescriptorProto_ExtensionRange* msg, upb_Arena* arena) { struct google_protobuf_ExtensionRangeOptions* sub = (struct google_protobuf_ExtensionRangeOptions*)google_protobuf_DescriptorProto_ExtensionRange_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_ExtensionRangeOptions*)_upb_Message_New(&google_protobuf_ExtensionRangeOptions_msginit, arena); + sub = (struct google_protobuf_ExtensionRangeOptions*)_upb_Message_New(&google_protobuf_ExtensionRangeOptions_msg_init, arena); if (!sub) return NULL; google_protobuf_DescriptorProto_ExtensionRange_set_options(msg, sub); } @@ -2995,12 +3215,12 @@ UPB_INLINE struct google_protobuf_ExtensionRangeOptions* google_protobuf_Descrip /* google.protobuf.DescriptorProto.ReservedRange */ UPB_INLINE google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_ReservedRange_new(upb_Arena* arena) { - return (google_protobuf_DescriptorProto_ReservedRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ReservedRange_msginit, arena); + return (google_protobuf_DescriptorProto_ReservedRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ReservedRange_msg_init, arena); } UPB_INLINE google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_ReservedRange_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_DescriptorProto_ReservedRange* ret = google_protobuf_DescriptorProto_ReservedRange_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ReservedRange_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ReservedRange_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3010,28 +3230,40 @@ UPB_INLINE google_protobuf_DescriptorProto_ReservedRange* google_protobuf_Descri int options, upb_Arena* arena) { google_protobuf_DescriptorProto_ReservedRange* ret = google_protobuf_DescriptorProto_ReservedRange_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ReservedRange_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ReservedRange_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_DescriptorProto_ReservedRange_serialize(const google_protobuf_DescriptorProto_ReservedRange* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_DescriptorProto_ReservedRange_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_DescriptorProto_ReservedRange_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_DescriptorProto_ReservedRange_serialize_ex(const google_protobuf_DescriptorProto_ReservedRange* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_DescriptorProto_ReservedRange_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_DescriptorProto_ReservedRange_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_start(const google_protobuf_DescriptorProto_ReservedRange* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_clear_start(const google_protobuf_DescriptorProto_ReservedRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_start(const google_protobuf_DescriptorProto_ReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_end(const google_protobuf_DescriptorProto_ReservedRange* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_clear_end(const google_protobuf_DescriptorProto_ReservedRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_end(const google_protobuf_DescriptorProto_ReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } @@ -3048,12 +3280,12 @@ UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_end(google_pro /* google.protobuf.ExtensionRangeOptions */ UPB_INLINE google_protobuf_ExtensionRangeOptions* google_protobuf_ExtensionRangeOptions_new(upb_Arena* arena) { - return (google_protobuf_ExtensionRangeOptions*)_upb_Message_New(&google_protobuf_ExtensionRangeOptions_msginit, arena); + return (google_protobuf_ExtensionRangeOptions*)_upb_Message_New(&google_protobuf_ExtensionRangeOptions_msg_init, arena); } UPB_INLINE google_protobuf_ExtensionRangeOptions* google_protobuf_ExtensionRangeOptions_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_ExtensionRangeOptions* ret = google_protobuf_ExtensionRangeOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_ExtensionRangeOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_ExtensionRangeOptions_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3063,22 +3295,29 @@ UPB_INLINE google_protobuf_ExtensionRangeOptions* google_protobuf_ExtensionRange int options, upb_Arena* arena) { google_protobuf_ExtensionRangeOptions* ret = google_protobuf_ExtensionRangeOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_ExtensionRangeOptions_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_ExtensionRangeOptions_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_ExtensionRangeOptions_serialize(const google_protobuf_ExtensionRangeOptions* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_ExtensionRangeOptions_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_ExtensionRangeOptions_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_ExtensionRangeOptions_serialize_ex(const google_protobuf_ExtensionRangeOptions* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_ExtensionRangeOptions_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_ExtensionRangeOptions_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_ExtensionRangeOptions_has_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } +UPB_INLINE void google_protobuf_ExtensionRangeOptions_clear_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); +} UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ExtensionRangeOptions_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg, size_t* len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } @@ -3090,7 +3329,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeO return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ExtensionRangeOptions_add_uninterpreted_option(google_protobuf_ExtensionRangeOptions* msg, upb_Arena* arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; @@ -3099,12 +3338,12 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_Extension /* google.protobuf.FieldDescriptorProto */ UPB_INLINE google_protobuf_FieldDescriptorProto* google_protobuf_FieldDescriptorProto_new(upb_Arena* arena) { - return (google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena); + return (google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msg_init, arena); } UPB_INLINE google_protobuf_FieldDescriptorProto* google_protobuf_FieldDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_FieldDescriptorProto* ret = google_protobuf_FieldDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FieldDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_FieldDescriptorProto_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3114,82 +3353,130 @@ UPB_INLINE google_protobuf_FieldDescriptorProto* google_protobuf_FieldDescriptor int options, upb_Arena* arena) { google_protobuf_FieldDescriptorProto* ret = google_protobuf_FieldDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FieldDescriptorProto_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_FieldDescriptorProto_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_FieldDescriptorProto_serialize(const google_protobuf_FieldDescriptorProto* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FieldDescriptorProto_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FieldDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_FieldDescriptorProto_serialize_ex(const google_protobuf_FieldDescriptorProto* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FieldDescriptorProto_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FieldDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_name(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_name(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(24, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_name(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), upb_StringView); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_extendee(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_extendee(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(32, 40), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_extendee(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 40), upb_StringView); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_number(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_number(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 3); +} UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_number(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t); + return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_label(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_label(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 4); +} UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_label(const google_protobuf_FieldDescriptorProto* msg) { - return google_protobuf_FieldDescriptorProto_has_label(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) : 1; + return google_protobuf_FieldDescriptorProto_has_label(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) : 1; } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_type(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = 0; + _upb_clearhas(msg, 5); +} UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_type(const google_protobuf_FieldDescriptorProto* msg) { - return google_protobuf_FieldDescriptorProto_has_type(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) : 1; + return google_protobuf_FieldDescriptorProto_has_type(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) : 1; } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type_name(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 6); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_type_name(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(40, 56), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 6); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_type_name(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(40, 56), upb_StringView); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_default_value(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 7); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_default_value(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(48, 72), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 7); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_default_value(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(48, 72), upb_StringView); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_options(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 8); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_options(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(56, 88), const upb_Message*) = NULL; + _upb_clearhas(msg, 8); +} UPB_INLINE const google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_options(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(64, 104), const google_protobuf_FieldOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(56, 88), const google_protobuf_FieldOptions*); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 9); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t) = 0; + _upb_clearhas(msg, 9); +} UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_json_name(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 10); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_json_name(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(60, 96), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 10); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_json_name(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(56, 88), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(60, 96), upb_StringView); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 11); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(20, 20), bool) = 0; + _upb_clearhas(msg, 11); +} UPB_INLINE bool google_protobuf_FieldDescriptorProto_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 20), bool); } @@ -3204,15 +3491,15 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_set_extendee(google_protobu } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_number(google_protobuf_FieldDescriptorProto *msg, int32_t value) { _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_label(google_protobuf_FieldDescriptorProto *msg, int32_t value) { _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type(google_protobuf_FieldDescriptorProto *msg, int32_t value) { _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = value; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 6); @@ -3224,12 +3511,12 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_set_default_value(google_pr } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_options(google_protobuf_FieldDescriptorProto *msg, google_protobuf_FieldOptions* value) { _upb_sethas(msg, 8); - *UPB_PTR_AT(msg, UPB_SIZE(64, 104), google_protobuf_FieldOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(56, 88), google_protobuf_FieldOptions*) = value; } UPB_INLINE struct google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_mutable_options(google_protobuf_FieldDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_FieldOptions* sub = (struct google_protobuf_FieldOptions*)google_protobuf_FieldDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_FieldOptions*)_upb_Message_New(&google_protobuf_FieldOptions_msginit, arena); + sub = (struct google_protobuf_FieldOptions*)_upb_Message_New(&google_protobuf_FieldOptions_msg_init, arena); if (!sub) return NULL; google_protobuf_FieldDescriptorProto_set_options(msg, sub); } @@ -3241,7 +3528,7 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_set_oneof_index(google_prot } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_json_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 10); - *UPB_PTR_AT(msg, UPB_SIZE(56, 88), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(60, 96), upb_StringView) = value; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_proto3_optional(google_protobuf_FieldDescriptorProto *msg, bool value) { _upb_sethas(msg, 11); @@ -3251,12 +3538,12 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_set_proto3_optional(google_ /* google.protobuf.OneofDescriptorProto */ UPB_INLINE google_protobuf_OneofDescriptorProto* google_protobuf_OneofDescriptorProto_new(upb_Arena* arena) { - return (google_protobuf_OneofDescriptorProto*)_upb_Message_New(&google_protobuf_OneofDescriptorProto_msginit, arena); + return (google_protobuf_OneofDescriptorProto*)_upb_Message_New(&google_protobuf_OneofDescriptorProto_msg_init, arena); } UPB_INLINE google_protobuf_OneofDescriptorProto* google_protobuf_OneofDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_OneofDescriptorProto* ret = google_protobuf_OneofDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_OneofDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_OneofDescriptorProto_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3266,28 +3553,40 @@ UPB_INLINE google_protobuf_OneofDescriptorProto* google_protobuf_OneofDescriptor int options, upb_Arena* arena) { google_protobuf_OneofDescriptorProto* ret = google_protobuf_OneofDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_OneofDescriptorProto_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_OneofDescriptorProto_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_OneofDescriptorProto_serialize(const google_protobuf_OneofDescriptorProto* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_OneofDescriptorProto_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_OneofDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_OneofDescriptorProto_serialize_ex(const google_protobuf_OneofDescriptorProto* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_OneofDescriptorProto_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_OneofDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_name(const google_protobuf_OneofDescriptorProto* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_OneofDescriptorProto_clear_name(const google_protobuf_OneofDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_OneofDescriptorProto_name(const google_protobuf_OneofDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_options(const google_protobuf_OneofDescriptorProto* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_OneofDescriptorProto_clear_options(const google_protobuf_OneofDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const upb_Message*) = NULL; + _upb_clearhas(msg, 2); +} UPB_INLINE const google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_options(const google_protobuf_OneofDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_OneofOptions*); } @@ -3303,7 +3602,7 @@ UPB_INLINE void google_protobuf_OneofDescriptorProto_set_options(google_protobuf UPB_INLINE struct google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_mutable_options(google_protobuf_OneofDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_OneofOptions* sub = (struct google_protobuf_OneofOptions*)google_protobuf_OneofDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_OneofOptions*)_upb_Message_New(&google_protobuf_OneofOptions_msginit, arena); + sub = (struct google_protobuf_OneofOptions*)_upb_Message_New(&google_protobuf_OneofOptions_msg_init, arena); if (!sub) return NULL; google_protobuf_OneofDescriptorProto_set_options(msg, sub); } @@ -3313,12 +3612,12 @@ UPB_INLINE struct google_protobuf_OneofOptions* google_protobuf_OneofDescriptorP /* google.protobuf.EnumDescriptorProto */ UPB_INLINE google_protobuf_EnumDescriptorProto* google_protobuf_EnumDescriptorProto_new(upb_Arena* arena) { - return (google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msginit, arena); + return (google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msg_init, arena); } UPB_INLINE google_protobuf_EnumDescriptorProto* google_protobuf_EnumDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_EnumDescriptorProto* ret = google_protobuf_EnumDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3328,43 +3627,64 @@ UPB_INLINE google_protobuf_EnumDescriptorProto* google_protobuf_EnumDescriptorPr int options, upb_Arena* arena) { google_protobuf_EnumDescriptorProto* ret = google_protobuf_EnumDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_EnumDescriptorProto_serialize(const google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumDescriptorProto_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_EnumDescriptorProto_serialize_ex(const google_protobuf_EnumDescriptorProto* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumDescriptorProto_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_name(const google_protobuf_EnumDescriptorProto* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_name(const google_protobuf_EnumDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_EnumDescriptorProto_name(const google_protobuf_EnumDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_value(const google_protobuf_EnumDescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 24)); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_value(const google_protobuf_EnumDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(12, 24)); } UPB_INLINE const google_protobuf_EnumValueDescriptorProto* const* google_protobuf_EnumDescriptorProto_value(const google_protobuf_EnumDescriptorProto* msg, size_t* len) { - return (const google_protobuf_EnumValueDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); + return (const google_protobuf_EnumValueDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(12, 24), len); } UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_options(const google_protobuf_EnumDescriptorProto* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_options(const google_protobuf_EnumDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const upb_Message*) = NULL; + _upb_clearhas(msg, 2); +} UPB_INLINE const google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_options(const google_protobuf_EnumDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_EnumOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const google_protobuf_EnumOptions*); } UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_reserved_range(const google_protobuf_EnumDescriptorProto* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); } +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_reserved_range(const google_protobuf_EnumDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(20, 40)); +} UPB_INLINE const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* google_protobuf_EnumDescriptorProto_reserved_range(const google_protobuf_EnumDescriptorProto* msg, size_t* len) { return (const google_protobuf_EnumDescriptorProto_EnumReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); } +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_reserved_name(const google_protobuf_EnumDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(24, 48)); +} UPB_INLINE upb_StringView const* google_protobuf_EnumDescriptorProto_reserved_name(const google_protobuf_EnumDescriptorProto* msg, size_t* len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } @@ -3374,25 +3694,25 @@ UPB_INLINE void google_protobuf_EnumDescriptorProto_set_name(google_protobuf_Enu *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; } UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_mutable_value(google_protobuf_EnumDescriptorProto* msg, size_t* len) { - return (google_protobuf_EnumValueDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); + return (google_protobuf_EnumValueDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 24), len); } UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_resize_value(google_protobuf_EnumDescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_EnumValueDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_EnumValueDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 24), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumDescriptorProto_add_value(google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { - struct google_protobuf_EnumValueDescriptorProto* sub = (struct google_protobuf_EnumValueDescriptorProto*)_upb_Message_New(&google_protobuf_EnumValueDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); + struct google_protobuf_EnumValueDescriptorProto* sub = (struct google_protobuf_EnumValueDescriptorProto*)_upb_Message_New(&google_protobuf_EnumValueDescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(12, 24), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_EnumDescriptorProto_set_options(google_protobuf_EnumDescriptorProto *msg, google_protobuf_EnumOptions* value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_EnumOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), google_protobuf_EnumOptions*) = value; } UPB_INLINE struct google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_mutable_options(google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumOptions* sub = (struct google_protobuf_EnumOptions*)google_protobuf_EnumDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_EnumOptions*)_upb_Message_New(&google_protobuf_EnumOptions_msginit, arena); + sub = (struct google_protobuf_EnumOptions*)_upb_Message_New(&google_protobuf_EnumOptions_msg_init, arena); if (!sub) return NULL; google_protobuf_EnumDescriptorProto_set_options(msg, sub); } @@ -3405,7 +3725,7 @@ UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protob return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_add_reserved_range(google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { - struct google_protobuf_EnumDescriptorProto_EnumReservedRange* sub = (struct google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena); + struct google_protobuf_EnumDescriptorProto_EnumReservedRange* sub = (struct google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init, arena); bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; @@ -3423,12 +3743,12 @@ UPB_INLINE bool google_protobuf_EnumDescriptorProto_add_reserved_name(google_pro /* google.protobuf.EnumDescriptorProto.EnumReservedRange */ UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_EnumReservedRange_new(upb_Arena* arena) { - return (google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena); + return (google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init, arena); } UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_EnumReservedRange_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_EnumDescriptorProto_EnumReservedRange* ret = google_protobuf_EnumDescriptorProto_EnumReservedRange_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3438,28 +3758,40 @@ UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobu int options, upb_Arena* arena) { google_protobuf_EnumDescriptorProto_EnumReservedRange* ret = google_protobuf_EnumDescriptorProto_EnumReservedRange_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize_ex(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_clear_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_clear_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } @@ -3476,12 +3808,12 @@ UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_end(go /* google.protobuf.EnumValueDescriptorProto */ UPB_INLINE google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumValueDescriptorProto_new(upb_Arena* arena) { - return (google_protobuf_EnumValueDescriptorProto*)_upb_Message_New(&google_protobuf_EnumValueDescriptorProto_msginit, arena); + return (google_protobuf_EnumValueDescriptorProto*)_upb_Message_New(&google_protobuf_EnumValueDescriptorProto_msg_init, arena); } UPB_INLINE google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumValueDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_EnumValueDescriptorProto* ret = google_protobuf_EnumValueDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueDescriptorProto_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3491,34 +3823,50 @@ UPB_INLINE google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumValueDe int options, upb_Arena* arena) { google_protobuf_EnumValueDescriptorProto* ret = google_protobuf_EnumValueDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueDescriptorProto_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueDescriptorProto_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_EnumValueDescriptorProto_serialize(const google_protobuf_EnumValueDescriptorProto* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumValueDescriptorProto_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumValueDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_EnumValueDescriptorProto_serialize_ex(const google_protobuf_EnumValueDescriptorProto* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumValueDescriptorProto_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumValueDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_name(const google_protobuf_EnumValueDescriptorProto* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_name(const google_protobuf_EnumValueDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_EnumValueDescriptorProto_name(const google_protobuf_EnumValueDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_StringView); } UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_number(const google_protobuf_EnumValueDescriptorProto* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_number(const google_protobuf_EnumValueDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE int32_t google_protobuf_EnumValueDescriptorProto_number(const google_protobuf_EnumValueDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_options(const google_protobuf_EnumValueDescriptorProto* msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_options(const google_protobuf_EnumValueDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 24), const upb_Message*) = NULL; + _upb_clearhas(msg, 3); +} UPB_INLINE const google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_options(const google_protobuf_EnumValueDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 24), const google_protobuf_EnumValueOptions*); } @@ -3538,7 +3886,7 @@ UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_options(google_prot UPB_INLINE struct google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_mutable_options(google_protobuf_EnumValueDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumValueOptions* sub = (struct google_protobuf_EnumValueOptions*)google_protobuf_EnumValueDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_EnumValueOptions*)_upb_Message_New(&google_protobuf_EnumValueOptions_msginit, arena); + sub = (struct google_protobuf_EnumValueOptions*)_upb_Message_New(&google_protobuf_EnumValueOptions_msg_init, arena); if (!sub) return NULL; google_protobuf_EnumValueDescriptorProto_set_options(msg, sub); } @@ -3548,12 +3896,12 @@ UPB_INLINE struct google_protobuf_EnumValueOptions* google_protobuf_EnumValueDes /* google.protobuf.ServiceDescriptorProto */ UPB_INLINE google_protobuf_ServiceDescriptorProto* google_protobuf_ServiceDescriptorProto_new(upb_Arena* arena) { - return (google_protobuf_ServiceDescriptorProto*)_upb_Message_New(&google_protobuf_ServiceDescriptorProto_msginit, arena); + return (google_protobuf_ServiceDescriptorProto*)_upb_Message_New(&google_protobuf_ServiceDescriptorProto_msg_init, arena); } UPB_INLINE google_protobuf_ServiceDescriptorProto* google_protobuf_ServiceDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_ServiceDescriptorProto* ret = google_protobuf_ServiceDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_ServiceDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_ServiceDescriptorProto_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3563,36 +3911,51 @@ UPB_INLINE google_protobuf_ServiceDescriptorProto* google_protobuf_ServiceDescri int options, upb_Arena* arena) { google_protobuf_ServiceDescriptorProto* ret = google_protobuf_ServiceDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_ServiceDescriptorProto_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_ServiceDescriptorProto_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_ServiceDescriptorProto_serialize(const google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_ServiceDescriptorProto_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_ServiceDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_ServiceDescriptorProto_serialize_ex(const google_protobuf_ServiceDescriptorProto* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_ServiceDescriptorProto_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_ServiceDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_name(const google_protobuf_ServiceDescriptorProto* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_name(const google_protobuf_ServiceDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_ServiceDescriptorProto_name(const google_protobuf_ServiceDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_method(const google_protobuf_ServiceDescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 24)); +} +UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_method(const google_protobuf_ServiceDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(12, 24)); } UPB_INLINE const google_protobuf_MethodDescriptorProto* const* google_protobuf_ServiceDescriptorProto_method(const google_protobuf_ServiceDescriptorProto* msg, size_t* len) { - return (const google_protobuf_MethodDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); + return (const google_protobuf_MethodDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(12, 24), len); } UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_options(const google_protobuf_ServiceDescriptorProto* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_options(const google_protobuf_ServiceDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const upb_Message*) = NULL; + _upb_clearhas(msg, 2); +} UPB_INLINE const google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_options(const google_protobuf_ServiceDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_ServiceOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const google_protobuf_ServiceOptions*); } UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_name(google_protobuf_ServiceDescriptorProto *msg, upb_StringView value) { @@ -3600,25 +3963,25 @@ UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_name(google_protobuf_ *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; } UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_mutable_method(google_protobuf_ServiceDescriptorProto* msg, size_t* len) { - return (google_protobuf_MethodDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); + return (google_protobuf_MethodDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 24), len); } UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_resize_method(google_protobuf_ServiceDescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_MethodDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_MethodDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 24), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_MethodDescriptorProto* google_protobuf_ServiceDescriptorProto_add_method(google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena) { - struct google_protobuf_MethodDescriptorProto* sub = (struct google_protobuf_MethodDescriptorProto*)_upb_Message_New(&google_protobuf_MethodDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); + struct google_protobuf_MethodDescriptorProto* sub = (struct google_protobuf_MethodDescriptorProto*)_upb_Message_New(&google_protobuf_MethodDescriptorProto_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(12, 24), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_options(google_protobuf_ServiceDescriptorProto *msg, google_protobuf_ServiceOptions* value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_ServiceOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), google_protobuf_ServiceOptions*) = value; } UPB_INLINE struct google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_mutable_options(google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_ServiceOptions* sub = (struct google_protobuf_ServiceOptions*)google_protobuf_ServiceDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_ServiceOptions*)_upb_Message_New(&google_protobuf_ServiceOptions_msginit, arena); + sub = (struct google_protobuf_ServiceOptions*)_upb_Message_New(&google_protobuf_ServiceOptions_msg_init, arena); if (!sub) return NULL; google_protobuf_ServiceDescriptorProto_set_options(msg, sub); } @@ -3628,12 +3991,12 @@ UPB_INLINE struct google_protobuf_ServiceOptions* google_protobuf_ServiceDescrip /* google.protobuf.MethodDescriptorProto */ UPB_INLINE google_protobuf_MethodDescriptorProto* google_protobuf_MethodDescriptorProto_new(upb_Arena* arena) { - return (google_protobuf_MethodDescriptorProto*)_upb_Message_New(&google_protobuf_MethodDescriptorProto_msginit, arena); + return (google_protobuf_MethodDescriptorProto*)_upb_Message_New(&google_protobuf_MethodDescriptorProto_msg_init, arena); } UPB_INLINE google_protobuf_MethodDescriptorProto* google_protobuf_MethodDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_MethodDescriptorProto* ret = google_protobuf_MethodDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_MethodDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_MethodDescriptorProto_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3643,52 +4006,80 @@ UPB_INLINE google_protobuf_MethodDescriptorProto* google_protobuf_MethodDescript int options, upb_Arena* arena) { google_protobuf_MethodDescriptorProto* ret = google_protobuf_MethodDescriptorProto_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_MethodDescriptorProto_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_MethodDescriptorProto_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_MethodDescriptorProto_serialize(const google_protobuf_MethodDescriptorProto* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_MethodDescriptorProto_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_MethodDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_MethodDescriptorProto_serialize_ex(const google_protobuf_MethodDescriptorProto* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_MethodDescriptorProto_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_MethodDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_name(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_name(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_name(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_input_type(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_input_type(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_input_type(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_output_type(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_output_type(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 3); +} UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_output_type(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView); } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_options(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_options(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const upb_Message*) = NULL; + _upb_clearhas(msg, 4); +} UPB_INLINE const google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_options(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const google_protobuf_MethodOptions*); } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 5); +} UPB_INLINE bool google_protobuf_MethodDescriptorProto_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 6); } +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = 0; + _upb_clearhas(msg, 6); +} UPB_INLINE bool google_protobuf_MethodDescriptorProto_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); } @@ -3712,7 +4103,7 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_set_options(google_protobu UPB_INLINE struct google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_mutable_options(google_protobuf_MethodDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_MethodOptions* sub = (struct google_protobuf_MethodOptions*)google_protobuf_MethodDescriptorProto_options(msg); if (sub == NULL) { - sub = (struct google_protobuf_MethodOptions*)_upb_Message_New(&google_protobuf_MethodOptions_msginit, arena); + sub = (struct google_protobuf_MethodOptions*)_upb_Message_New(&google_protobuf_MethodOptions_msg_init, arena); if (!sub) return NULL; google_protobuf_MethodDescriptorProto_set_options(msg, sub); } @@ -3730,12 +4121,12 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_set_server_streaming(googl /* google.protobuf.FileOptions */ UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_new(upb_Arena* arena) { - return (google_protobuf_FileOptions*)_upb_Message_New(&google_protobuf_FileOptions_msginit, arena); + return (google_protobuf_FileOptions*)_upb_Message_New(&google_protobuf_FileOptions_msg_init, arena); } UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_FileOptions* ret = google_protobuf_FileOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FileOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_FileOptions_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3745,142 +4136,229 @@ UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_parse_ex(con int options, upb_Arena* arena) { google_protobuf_FileOptions* ret = google_protobuf_FileOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FileOptions_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_FileOptions_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_FileOptions_serialize(const google_protobuf_FileOptions* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FileOptions_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FileOptions_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_FileOptions_serialize_ex(const google_protobuf_FileOptions* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FileOptions_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FileOptions_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_FileOptions_has_java_package(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_FileOptions_clear_java_package(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_java_package(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_java_outer_classname(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_FileOptions_clear_java_outer_classname(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(28, 40), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_java_outer_classname(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 40), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_optimize_for(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_FileOptions_clear_optimize_for(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 3); +} UPB_INLINE int32_t google_protobuf_FileOptions_optimize_for(const google_protobuf_FileOptions* msg) { return google_protobuf_FileOptions_has_optimize_for(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) : 1; } UPB_INLINE bool google_protobuf_FileOptions_has_java_multiple_files(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE void google_protobuf_FileOptions_clear_java_multiple_files(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = 0; + _upb_clearhas(msg, 4); +} UPB_INLINE bool google_protobuf_FileOptions_java_multiple_files(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool); } UPB_INLINE bool google_protobuf_FileOptions_has_go_package(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE void google_protobuf_FileOptions_clear_go_package(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(36, 56), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 5); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_go_package(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(36, 56), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_cc_generic_services(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 6); } +UPB_INLINE void google_protobuf_FileOptions_clear_cc_generic_services(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool) = 0; + _upb_clearhas(msg, 6); +} UPB_INLINE bool google_protobuf_FileOptions_cc_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool); } UPB_INLINE bool google_protobuf_FileOptions_has_java_generic_services(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 7); } +UPB_INLINE void google_protobuf_FileOptions_clear_java_generic_services(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool) = 0; + _upb_clearhas(msg, 7); +} UPB_INLINE bool google_protobuf_FileOptions_java_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool); } UPB_INLINE bool google_protobuf_FileOptions_has_py_generic_services(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 8); } +UPB_INLINE void google_protobuf_FileOptions_clear_py_generic_services(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(11, 11), bool) = 0; + _upb_clearhas(msg, 8); +} UPB_INLINE bool google_protobuf_FileOptions_py_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(11, 11), bool); } UPB_INLINE bool google_protobuf_FileOptions_has_java_generate_equals_and_hash(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 9); } +UPB_INLINE void google_protobuf_FileOptions_clear_java_generate_equals_and_hash(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool) = 0; + _upb_clearhas(msg, 9); +} UPB_INLINE bool google_protobuf_FileOptions_java_generate_equals_and_hash(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool); } UPB_INLINE bool google_protobuf_FileOptions_has_deprecated(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 10); } +UPB_INLINE void google_protobuf_FileOptions_clear_deprecated(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool) = 0; + _upb_clearhas(msg, 10); +} UPB_INLINE bool google_protobuf_FileOptions_deprecated(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool); } UPB_INLINE bool google_protobuf_FileOptions_has_java_string_check_utf8(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 11); } +UPB_INLINE void google_protobuf_FileOptions_clear_java_string_check_utf8(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool) = 0; + _upb_clearhas(msg, 11); +} UPB_INLINE bool google_protobuf_FileOptions_java_string_check_utf8(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool); } UPB_INLINE bool google_protobuf_FileOptions_has_cc_enable_arenas(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 12); } +UPB_INLINE void google_protobuf_FileOptions_clear_cc_enable_arenas(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) = 0; + _upb_clearhas(msg, 12); +} UPB_INLINE bool google_protobuf_FileOptions_cc_enable_arenas(const google_protobuf_FileOptions* msg) { return google_protobuf_FileOptions_has_cc_enable_arenas(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) : true; } UPB_INLINE bool google_protobuf_FileOptions_has_objc_class_prefix(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 13); } +UPB_INLINE void google_protobuf_FileOptions_clear_objc_class_prefix(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(44, 72), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 13); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_objc_class_prefix(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(44, 72), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_csharp_namespace(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 14); } +UPB_INLINE void google_protobuf_FileOptions_clear_csharp_namespace(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(52, 88), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 14); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_csharp_namespace(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(52, 88), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_swift_prefix(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 15); } +UPB_INLINE void google_protobuf_FileOptions_clear_swift_prefix(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(60, 104), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 15); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_swift_prefix(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(60, 104), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_php_class_prefix(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 16); } +UPB_INLINE void google_protobuf_FileOptions_clear_php_class_prefix(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(68, 120), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 16); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_php_class_prefix(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(68, 120), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_php_namespace(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 17); } +UPB_INLINE void google_protobuf_FileOptions_clear_php_namespace(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(76, 136), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 17); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_php_namespace(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(76, 136), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_php_generic_services(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 18); } +UPB_INLINE void google_protobuf_FileOptions_clear_php_generic_services(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = 0; + _upb_clearhas(msg, 18); +} UPB_INLINE bool google_protobuf_FileOptions_php_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); } UPB_INLINE bool google_protobuf_FileOptions_has_php_metadata_namespace(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 19); } +UPB_INLINE void google_protobuf_FileOptions_clear_php_metadata_namespace(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(84, 152), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 19); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_php_metadata_namespace(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(84, 152), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_ruby_package(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 20); } +UPB_INLINE void google_protobuf_FileOptions_clear_ruby_package(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(92, 168), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 20); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_ruby_package(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(92, 168), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_uninterpreted_option(const google_protobuf_FileOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(100, 184)); } +UPB_INLINE void google_protobuf_FileOptions_clear_uninterpreted_option(const google_protobuf_FileOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(100, 184)); +} UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FileOptions_uninterpreted_option(const google_protobuf_FileOptions* msg, size_t* len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(100, 184), len); } @@ -3972,7 +4450,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_res return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(100, 184), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FileOptions_add_uninterpreted_option(google_protobuf_FileOptions* msg, upb_Arena* arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(100, 184), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; @@ -3981,12 +4459,12 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FileOptio /* google.protobuf.MessageOptions */ UPB_INLINE google_protobuf_MessageOptions* google_protobuf_MessageOptions_new(upb_Arena* arena) { - return (google_protobuf_MessageOptions*)_upb_Message_New(&google_protobuf_MessageOptions_msginit, arena); + return (google_protobuf_MessageOptions*)_upb_Message_New(&google_protobuf_MessageOptions_msg_init, arena); } UPB_INLINE google_protobuf_MessageOptions* google_protobuf_MessageOptions_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_MessageOptions* ret = google_protobuf_MessageOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_MessageOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_MessageOptions_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -3996,46 +4474,69 @@ UPB_INLINE google_protobuf_MessageOptions* google_protobuf_MessageOptions_parse_ int options, upb_Arena* arena) { google_protobuf_MessageOptions* ret = google_protobuf_MessageOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_MessageOptions_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_MessageOptions_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_MessageOptions_serialize(const google_protobuf_MessageOptions* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_MessageOptions_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_MessageOptions_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_MessageOptions_serialize_ex(const google_protobuf_MessageOptions* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_MessageOptions_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_MessageOptions_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_MessageOptions_has_message_set_wire_format(const google_protobuf_MessageOptions* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_MessageOptions_clear_message_set_wire_format(const google_protobuf_MessageOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE bool google_protobuf_MessageOptions_message_set_wire_format(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } UPB_INLINE bool google_protobuf_MessageOptions_has_no_standard_descriptor_accessor(const google_protobuf_MessageOptions* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_MessageOptions_clear_no_standard_descriptor_accessor(const google_protobuf_MessageOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE bool google_protobuf_MessageOptions_no_standard_descriptor_accessor(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); } UPB_INLINE bool google_protobuf_MessageOptions_has_deprecated(const google_protobuf_MessageOptions* msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_MessageOptions_clear_deprecated(const google_protobuf_MessageOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool) = 0; + _upb_clearhas(msg, 3); +} UPB_INLINE bool google_protobuf_MessageOptions_deprecated(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool); } UPB_INLINE bool google_protobuf_MessageOptions_has_map_entry(const google_protobuf_MessageOptions* msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE void google_protobuf_MessageOptions_clear_map_entry(const google_protobuf_MessageOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), bool) = 0; + _upb_clearhas(msg, 4); +} UPB_INLINE bool google_protobuf_MessageOptions_map_entry(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), bool); } UPB_INLINE bool google_protobuf_MessageOptions_has_uninterpreted_option(const google_protobuf_MessageOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 8)); } +UPB_INLINE void google_protobuf_MessageOptions_clear_uninterpreted_option(const google_protobuf_MessageOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(8, 8)); +} UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MessageOptions_uninterpreted_option(const google_protobuf_MessageOptions* msg, size_t* len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(8, 8), len); } @@ -4063,7 +4564,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_ return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(8, 8), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MessageOptions_add_uninterpreted_option(google_protobuf_MessageOptions* msg, upb_Arena* arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(8, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; @@ -4072,12 +4573,12 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MessageOp /* google.protobuf.FieldOptions */ UPB_INLINE google_protobuf_FieldOptions* google_protobuf_FieldOptions_new(upb_Arena* arena) { - return (google_protobuf_FieldOptions*)_upb_Message_New(&google_protobuf_FieldOptions_msginit, arena); + return (google_protobuf_FieldOptions*)_upb_Message_New(&google_protobuf_FieldOptions_msg_init, arena); } UPB_INLINE google_protobuf_FieldOptions* google_protobuf_FieldOptions_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_FieldOptions* ret = google_protobuf_FieldOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FieldOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_FieldOptions_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -4087,64 +4588,99 @@ UPB_INLINE google_protobuf_FieldOptions* google_protobuf_FieldOptions_parse_ex(c int options, upb_Arena* arena) { google_protobuf_FieldOptions* ret = google_protobuf_FieldOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_FieldOptions_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_FieldOptions_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_FieldOptions_serialize(const google_protobuf_FieldOptions* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FieldOptions_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FieldOptions_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_FieldOptions_serialize_ex(const google_protobuf_FieldOptions* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_FieldOptions_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_FieldOptions_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_FieldOptions_has_ctype(const google_protobuf_FieldOptions* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_FieldOptions_clear_ctype(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE int32_t google_protobuf_FieldOptions_ctype(const google_protobuf_FieldOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } UPB_INLINE bool google_protobuf_FieldOptions_has_packed(const google_protobuf_FieldOptions* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_FieldOptions_clear_packed(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE bool google_protobuf_FieldOptions_packed(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool); } UPB_INLINE bool google_protobuf_FieldOptions_has_deprecated(const google_protobuf_FieldOptions* msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_FieldOptions_clear_deprecated(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool) = 0; + _upb_clearhas(msg, 3); +} UPB_INLINE bool google_protobuf_FieldOptions_deprecated(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool); } UPB_INLINE bool google_protobuf_FieldOptions_has_lazy(const google_protobuf_FieldOptions* msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE void google_protobuf_FieldOptions_clear_lazy(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool) = 0; + _upb_clearhas(msg, 4); +} UPB_INLINE bool google_protobuf_FieldOptions_lazy(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool); } UPB_INLINE bool google_protobuf_FieldOptions_has_jstype(const google_protobuf_FieldOptions* msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE void google_protobuf_FieldOptions_clear_jstype(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = 0; + _upb_clearhas(msg, 5); +} UPB_INLINE int32_t google_protobuf_FieldOptions_jstype(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); + return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t); } UPB_INLINE bool google_protobuf_FieldOptions_has_weak(const google_protobuf_FieldOptions* msg) { return _upb_hasbit(msg, 6); } +UPB_INLINE void google_protobuf_FieldOptions_clear_weak(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = 0; + _upb_clearhas(msg, 6); +} UPB_INLINE bool google_protobuf_FieldOptions_weak(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); } UPB_INLINE bool google_protobuf_FieldOptions_has_unverified_lazy(const google_protobuf_FieldOptions* msg) { return _upb_hasbit(msg, 7); } +UPB_INLINE void google_protobuf_FieldOptions_clear_unverified_lazy(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(17, 17), bool) = 0; + _upb_clearhas(msg, 7); +} UPB_INLINE bool google_protobuf_FieldOptions_unverified_lazy(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(17, 17), bool); } UPB_INLINE bool google_protobuf_FieldOptions_has_uninterpreted_option(const google_protobuf_FieldOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 24)); } +UPB_INLINE void google_protobuf_FieldOptions_clear_uninterpreted_option(const google_protobuf_FieldOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(20, 24)); +} UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FieldOptions_uninterpreted_option(const google_protobuf_FieldOptions* msg, size_t* len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(20, 24), len); } @@ -4155,27 +4691,27 @@ UPB_INLINE void google_protobuf_FieldOptions_set_ctype(google_protobuf_FieldOpti } UPB_INLINE void google_protobuf_FieldOptions_set_packed(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_deprecated(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_lazy(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_jstype(google_protobuf_FieldOptions *msg, int32_t value) { _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_weak(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 6); - *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_unverified_lazy(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 7); - *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(17, 17), bool) = value; } UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_mutable_uninterpreted_option(google_protobuf_FieldOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 24), len); @@ -4184,7 +4720,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_re return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 24), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FieldOptions_add_uninterpreted_option(google_protobuf_FieldOptions* msg, upb_Arena* arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 24), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; @@ -4193,12 +4729,12 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FieldOpti /* google.protobuf.OneofOptions */ UPB_INLINE google_protobuf_OneofOptions* google_protobuf_OneofOptions_new(upb_Arena* arena) { - return (google_protobuf_OneofOptions*)_upb_Message_New(&google_protobuf_OneofOptions_msginit, arena); + return (google_protobuf_OneofOptions*)_upb_Message_New(&google_protobuf_OneofOptions_msg_init, arena); } UPB_INLINE google_protobuf_OneofOptions* google_protobuf_OneofOptions_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_OneofOptions* ret = google_protobuf_OneofOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_OneofOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_OneofOptions_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -4208,22 +4744,29 @@ UPB_INLINE google_protobuf_OneofOptions* google_protobuf_OneofOptions_parse_ex(c int options, upb_Arena* arena) { google_protobuf_OneofOptions* ret = google_protobuf_OneofOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_OneofOptions_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_OneofOptions_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_OneofOptions_serialize(const google_protobuf_OneofOptions* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_OneofOptions_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_OneofOptions_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_OneofOptions_serialize_ex(const google_protobuf_OneofOptions* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_OneofOptions_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_OneofOptions_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_OneofOptions_has_uninterpreted_option(const google_protobuf_OneofOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } +UPB_INLINE void google_protobuf_OneofOptions_clear_uninterpreted_option(const google_protobuf_OneofOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); +} UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_OneofOptions_uninterpreted_option(const google_protobuf_OneofOptions* msg, size_t* len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } @@ -4235,7 +4778,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_re return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_OneofOptions_add_uninterpreted_option(google_protobuf_OneofOptions* msg, upb_Arena* arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; @@ -4244,12 +4787,12 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_OneofOpti /* google.protobuf.EnumOptions */ UPB_INLINE google_protobuf_EnumOptions* google_protobuf_EnumOptions_new(upb_Arena* arena) { - return (google_protobuf_EnumOptions*)_upb_Message_New(&google_protobuf_EnumOptions_msginit, arena); + return (google_protobuf_EnumOptions*)_upb_Message_New(&google_protobuf_EnumOptions_msg_init, arena); } UPB_INLINE google_protobuf_EnumOptions* google_protobuf_EnumOptions_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_EnumOptions* ret = google_protobuf_EnumOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_EnumOptions_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -4259,34 +4802,49 @@ UPB_INLINE google_protobuf_EnumOptions* google_protobuf_EnumOptions_parse_ex(con int options, upb_Arena* arena) { google_protobuf_EnumOptions* ret = google_protobuf_EnumOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumOptions_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_EnumOptions_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_EnumOptions_serialize(const google_protobuf_EnumOptions* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumOptions_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumOptions_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_EnumOptions_serialize_ex(const google_protobuf_EnumOptions* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumOptions_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumOptions_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_EnumOptions_has_allow_alias(const google_protobuf_EnumOptions* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_EnumOptions_clear_allow_alias(const google_protobuf_EnumOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE bool google_protobuf_EnumOptions_allow_alias(const google_protobuf_EnumOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } UPB_INLINE bool google_protobuf_EnumOptions_has_deprecated(const google_protobuf_EnumOptions* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_EnumOptions_clear_deprecated(const google_protobuf_EnumOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE bool google_protobuf_EnumOptions_deprecated(const google_protobuf_EnumOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); } UPB_INLINE bool google_protobuf_EnumOptions_has_uninterpreted_option(const google_protobuf_EnumOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); } +UPB_INLINE void google_protobuf_EnumOptions_clear_uninterpreted_option(const google_protobuf_EnumOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); +} UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumOptions_uninterpreted_option(const google_protobuf_EnumOptions* msg, size_t* len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } @@ -4306,7 +4864,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_res return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumOptions_add_uninterpreted_option(google_protobuf_EnumOptions* msg, upb_Arena* arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; @@ -4315,12 +4873,12 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumOptio /* google.protobuf.EnumValueOptions */ UPB_INLINE google_protobuf_EnumValueOptions* google_protobuf_EnumValueOptions_new(upb_Arena* arena) { - return (google_protobuf_EnumValueOptions*)_upb_Message_New(&google_protobuf_EnumValueOptions_msginit, arena); + return (google_protobuf_EnumValueOptions*)_upb_Message_New(&google_protobuf_EnumValueOptions_msg_init, arena); } UPB_INLINE google_protobuf_EnumValueOptions* google_protobuf_EnumValueOptions_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_EnumValueOptions* ret = google_protobuf_EnumValueOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueOptions_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -4330,28 +4888,39 @@ UPB_INLINE google_protobuf_EnumValueOptions* google_protobuf_EnumValueOptions_pa int options, upb_Arena* arena) { google_protobuf_EnumValueOptions* ret = google_protobuf_EnumValueOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueOptions_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueOptions_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_EnumValueOptions_serialize(const google_protobuf_EnumValueOptions* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumValueOptions_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumValueOptions_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_EnumValueOptions_serialize_ex(const google_protobuf_EnumValueOptions* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_EnumValueOptions_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_EnumValueOptions_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_EnumValueOptions_has_deprecated(const google_protobuf_EnumValueOptions* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_EnumValueOptions_clear_deprecated(const google_protobuf_EnumValueOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE bool google_protobuf_EnumValueOptions_deprecated(const google_protobuf_EnumValueOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } UPB_INLINE bool google_protobuf_EnumValueOptions_has_uninterpreted_option(const google_protobuf_EnumValueOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); } +UPB_INLINE void google_protobuf_EnumValueOptions_clear_uninterpreted_option(const google_protobuf_EnumValueOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); +} UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumValueOptions_uninterpreted_option(const google_protobuf_EnumValueOptions* msg, size_t* len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } @@ -4367,7 +4936,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOption return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumValueOptions_add_uninterpreted_option(google_protobuf_EnumValueOptions* msg, upb_Arena* arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; @@ -4376,12 +4945,12 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumValue /* google.protobuf.ServiceOptions */ UPB_INLINE google_protobuf_ServiceOptions* google_protobuf_ServiceOptions_new(upb_Arena* arena) { - return (google_protobuf_ServiceOptions*)_upb_Message_New(&google_protobuf_ServiceOptions_msginit, arena); + return (google_protobuf_ServiceOptions*)_upb_Message_New(&google_protobuf_ServiceOptions_msg_init, arena); } UPB_INLINE google_protobuf_ServiceOptions* google_protobuf_ServiceOptions_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_ServiceOptions* ret = google_protobuf_ServiceOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_ServiceOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_ServiceOptions_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -4391,28 +4960,39 @@ UPB_INLINE google_protobuf_ServiceOptions* google_protobuf_ServiceOptions_parse_ int options, upb_Arena* arena) { google_protobuf_ServiceOptions* ret = google_protobuf_ServiceOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_ServiceOptions_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_ServiceOptions_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_ServiceOptions_serialize(const google_protobuf_ServiceOptions* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_ServiceOptions_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_ServiceOptions_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_ServiceOptions_serialize_ex(const google_protobuf_ServiceOptions* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_ServiceOptions_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_ServiceOptions_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_ServiceOptions_has_deprecated(const google_protobuf_ServiceOptions* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_ServiceOptions_clear_deprecated(const google_protobuf_ServiceOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE bool google_protobuf_ServiceOptions_deprecated(const google_protobuf_ServiceOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } UPB_INLINE bool google_protobuf_ServiceOptions_has_uninterpreted_option(const google_protobuf_ServiceOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); } +UPB_INLINE void google_protobuf_ServiceOptions_clear_uninterpreted_option(const google_protobuf_ServiceOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); +} UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ServiceOptions_uninterpreted_option(const google_protobuf_ServiceOptions* msg, size_t* len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } @@ -4428,7 +5008,7 @@ UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_ return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ServiceOptions_add_uninterpreted_option(google_protobuf_ServiceOptions* msg, upb_Arena* arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; @@ -4437,12 +5017,12 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ServiceOp /* google.protobuf.MethodOptions */ UPB_INLINE google_protobuf_MethodOptions* google_protobuf_MethodOptions_new(upb_Arena* arena) { - return (google_protobuf_MethodOptions*)_upb_Message_New(&google_protobuf_MethodOptions_msginit, arena); + return (google_protobuf_MethodOptions*)_upb_Message_New(&google_protobuf_MethodOptions_msg_init, arena); } UPB_INLINE google_protobuf_MethodOptions* google_protobuf_MethodOptions_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_MethodOptions* ret = google_protobuf_MethodOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_MethodOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_MethodOptions_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -4452,55 +5032,70 @@ UPB_INLINE google_protobuf_MethodOptions* google_protobuf_MethodOptions_parse_ex int options, upb_Arena* arena) { google_protobuf_MethodOptions* ret = google_protobuf_MethodOptions_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_MethodOptions_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_MethodOptions_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_MethodOptions_serialize(const google_protobuf_MethodOptions* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_MethodOptions_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_MethodOptions_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_MethodOptions_serialize_ex(const google_protobuf_MethodOptions* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_MethodOptions_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_MethodOptions_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_MethodOptions_has_deprecated(const google_protobuf_MethodOptions* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_MethodOptions_clear_deprecated(const google_protobuf_MethodOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE bool google_protobuf_MethodOptions_deprecated(const google_protobuf_MethodOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } UPB_INLINE bool google_protobuf_MethodOptions_has_idempotency_level(const google_protobuf_MethodOptions* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_MethodOptions_clear_idempotency_level(const google_protobuf_MethodOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE int32_t google_protobuf_MethodOptions_idempotency_level(const google_protobuf_MethodOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } UPB_INLINE bool google_protobuf_MethodOptions_has_uninterpreted_option(const google_protobuf_MethodOptions* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 16)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 8)); +} +UPB_INLINE void google_protobuf_MethodOptions_clear_uninterpreted_option(const google_protobuf_MethodOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(8, 8)); } UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MethodOptions_uninterpreted_option(const google_protobuf_MethodOptions* msg, size_t* len) { - return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(12, 16), len); + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(8, 8), len); } UPB_INLINE void google_protobuf_MethodOptions_set_deprecated(google_protobuf_MethodOptions *msg, bool value) { _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; } UPB_INLINE void google_protobuf_MethodOptions_set_idempotency_level(google_protobuf_MethodOptions *msg, int32_t value) { _upb_sethas(msg, 2); *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; } UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_mutable_uninterpreted_option(google_protobuf_MethodOptions* msg, size_t* len) { - return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 16), len); + return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 8), len); } UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_resize_uninterpreted_option(google_protobuf_MethodOptions* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 16), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(8, 8), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MethodOptions_add_uninterpreted_option(google_protobuf_MethodOptions* msg, upb_Arena* arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(12, 16), UPB_SIZE(2, 3), &sub, arena); + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(8, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4508,12 +5103,12 @@ UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MethodOpt /* google.protobuf.UninterpretedOption */ UPB_INLINE google_protobuf_UninterpretedOption* google_protobuf_UninterpretedOption_new(upb_Arena* arena) { - return (google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); + return (google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, arena); } UPB_INLINE google_protobuf_UninterpretedOption* google_protobuf_UninterpretedOption_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_UninterpretedOption* ret = google_protobuf_UninterpretedOption_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -4523,108 +5118,139 @@ UPB_INLINE google_protobuf_UninterpretedOption* google_protobuf_UninterpretedOpt int options, upb_Arena* arena) { google_protobuf_UninterpretedOption* ret = google_protobuf_UninterpretedOption_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_UninterpretedOption_serialize(const google_protobuf_UninterpretedOption* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_UninterpretedOption_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_UninterpretedOption_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_UninterpretedOption_serialize_ex(const google_protobuf_UninterpretedOption* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_UninterpretedOption_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_UninterpretedOption_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_UninterpretedOption_has_name(const google_protobuf_UninterpretedOption* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(56, 80)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_name(const google_protobuf_UninterpretedOption* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); } UPB_INLINE const google_protobuf_UninterpretedOption_NamePart* const* google_protobuf_UninterpretedOption_name(const google_protobuf_UninterpretedOption* msg, size_t* len) { - return (const google_protobuf_UninterpretedOption_NamePart* const*)_upb_array_accessor(msg, UPB_SIZE(56, 80), len); + return (const google_protobuf_UninterpretedOption_NamePart* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } UPB_INLINE bool google_protobuf_UninterpretedOption_has_identifier_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_UninterpretedOption_clear_identifier_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 16), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_identifier_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(32, 32), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(8, 16), upb_StringView); } UPB_INLINE bool google_protobuf_UninterpretedOption_has_positive_int_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_UninterpretedOption_clear_positive_int_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(32, 64), uint64_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE uint64_t google_protobuf_UninterpretedOption_positive_int_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), uint64_t); + return *UPB_PTR_AT(msg, UPB_SIZE(32, 64), uint64_t); } UPB_INLINE bool google_protobuf_UninterpretedOption_has_negative_int_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_UninterpretedOption_clear_negative_int_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(40, 72), int64_t) = 0; + _upb_clearhas(msg, 3); +} UPB_INLINE int64_t google_protobuf_UninterpretedOption_negative_int_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int64_t); + return *UPB_PTR_AT(msg, UPB_SIZE(40, 72), int64_t); } UPB_INLINE bool google_protobuf_UninterpretedOption_has_double_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE void google_protobuf_UninterpretedOption_clear_double_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(48, 80), double) = 0; + _upb_clearhas(msg, 4); +} UPB_INLINE double google_protobuf_UninterpretedOption_double_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), double); + return *UPB_PTR_AT(msg, UPB_SIZE(48, 80), double); } UPB_INLINE bool google_protobuf_UninterpretedOption_has_string_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE void google_protobuf_UninterpretedOption_clear_string_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 5); +} UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_string_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(40, 48), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), upb_StringView); } UPB_INLINE bool google_protobuf_UninterpretedOption_has_aggregate_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 6); } +UPB_INLINE void google_protobuf_UninterpretedOption_clear_aggregate_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(24, 48), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 6); +} UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_aggregate_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(48, 64), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(24, 48), upb_StringView); } UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_mutable_name(google_protobuf_UninterpretedOption* msg, size_t* len) { - return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_mutable_accessor(msg, UPB_SIZE(56, 80), len); + return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); } UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_resize_name(google_protobuf_UninterpretedOption* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_UninterpretedOption_NamePart**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(56, 80), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_UninterpretedOption_NamePart**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_add_name(google_protobuf_UninterpretedOption* msg, upb_Arena* arena) { - struct google_protobuf_UninterpretedOption_NamePart* sub = (struct google_protobuf_UninterpretedOption_NamePart*)_upb_Message_New(&google_protobuf_UninterpretedOption_NamePart_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(56, 80), UPB_SIZE(2, 3), &sub, arena); + struct google_protobuf_UninterpretedOption_NamePart* sub = (struct google_protobuf_UninterpretedOption_NamePart*)_upb_Message_New(&google_protobuf_UninterpretedOption_NamePart_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_UninterpretedOption_set_identifier_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) { _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(32, 32), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(8, 16), upb_StringView) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_positive_int_value(google_protobuf_UninterpretedOption *msg, uint64_t value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), uint64_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(32, 64), uint64_t) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_negative_int_value(google_protobuf_UninterpretedOption *msg, int64_t value) { _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int64_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(40, 72), int64_t) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_double_value(google_protobuf_UninterpretedOption *msg, double value) { _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(24, 24), double) = value; + *UPB_PTR_AT(msg, UPB_SIZE(48, 80), double) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_string_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) { _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(40, 48), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), upb_StringView) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_aggregate_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) { _upb_sethas(msg, 6); - *UPB_PTR_AT(msg, UPB_SIZE(48, 64), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(24, 48), upb_StringView) = value; } /* google.protobuf.UninterpretedOption.NamePart */ UPB_INLINE google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_NamePart_new(upb_Arena* arena) { - return (google_protobuf_UninterpretedOption_NamePart*)_upb_Message_New(&google_protobuf_UninterpretedOption_NamePart_msginit, arena); + return (google_protobuf_UninterpretedOption_NamePart*)_upb_Message_New(&google_protobuf_UninterpretedOption_NamePart_msg_init, arena); } UPB_INLINE google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_NamePart_parse(const char* buf, size_t size, upb_Arena* arena) { google_protobuf_UninterpretedOption_NamePart* ret = google_protobuf_UninterpretedOption_NamePart_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_NamePart_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_NamePart_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; @@ -4634,28 +5260,40 @@ UPB_INLINE google_protobuf_UninterpretedOption_NamePart* google_protobuf_Uninter int options, upb_Arena* arena) { google_protobuf_UninterpretedOption_NamePart* ret = google_protobuf_UninterpretedOption_NamePart_new(arena); if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_NamePart_msginit, extreg, options, arena) != + if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_NamePart_msg_init, extreg, options, arena) != kUpb_DecodeStatus_Ok) { return NULL; } return ret; } UPB_INLINE char* google_protobuf_UninterpretedOption_NamePart_serialize(const google_protobuf_UninterpretedOption_NamePart* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_UninterpretedOption_NamePart_msginit, 0, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_UninterpretedOption_NamePart_msg_init, 0, arena, &ptr, len); + return ptr; } UPB_INLINE char* google_protobuf_UninterpretedOption_NamePart_serialize_ex(const google_protobuf_UninterpretedOption_NamePart* msg, int options, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_UninterpretedOption_NamePart_msginit, options, arena, len); + char* ptr; + (void)upb_Encode(msg, &google_protobuf_UninterpretedOption_NamePart_msg_init, options, arena, &ptr, len); + return ptr; } UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_name_part(const google_protobuf_UninterpretedOption_NamePart* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_clear_name_part(const google_protobuf_UninterpretedOption_NamePart* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_NamePart_name_part(const google_protobuf_UninterpretedOption_NamePart* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_is_extension(const google_protobuf_UninterpretedOption_NamePart* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_clear_is_extension(const google_protobuf_UninterpretedOption_NamePart* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_is_extension(const google_protobuf_UninterpretedOption_NamePart* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } @@ -4669,912 +5307,1964 @@ UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_is_extension(go *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; } -/* google.protobuf.SourceCodeInfo */ +/* google.protobuf.SourceCodeInfo */ + +UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_new(upb_Arena* arena) { + return (google_protobuf_SourceCodeInfo*)_upb_Message_New(&google_protobuf_SourceCodeInfo_msg_init, arena); +} +UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_SourceCodeInfo* ret = google_protobuf_SourceCodeInfo_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_SourceCodeInfo* ret = google_protobuf_SourceCodeInfo_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_msg_init, extreg, options, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_SourceCodeInfo_serialize(const google_protobuf_SourceCodeInfo* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, &google_protobuf_SourceCodeInfo_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_SourceCodeInfo_serialize_ex(const google_protobuf_SourceCodeInfo* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, &google_protobuf_SourceCodeInfo_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_has_location(const google_protobuf_SourceCodeInfo* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_clear_location(const google_protobuf_SourceCodeInfo* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE const google_protobuf_SourceCodeInfo_Location* const* google_protobuf_SourceCodeInfo_location(const google_protobuf_SourceCodeInfo* msg, size_t* len) { + return (const google_protobuf_SourceCodeInfo_Location* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); +} + +UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_mutable_location(google_protobuf_SourceCodeInfo* msg, size_t* len) { + return (google_protobuf_SourceCodeInfo_Location**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); +} +UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_resize_location(google_protobuf_SourceCodeInfo* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_SourceCodeInfo_Location**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); +} +UPB_INLINE struct google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_add_location(google_protobuf_SourceCodeInfo* msg, upb_Arena* arena) { + struct google_protobuf_SourceCodeInfo_Location* sub = (struct google_protobuf_SourceCodeInfo_Location*)_upb_Message_New(&google_protobuf_SourceCodeInfo_Location_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); + if (!ok) return NULL; + return sub; +} + +/* google.protobuf.SourceCodeInfo.Location */ + +UPB_INLINE google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_Location_new(upb_Arena* arena) { + return (google_protobuf_SourceCodeInfo_Location*)_upb_Message_New(&google_protobuf_SourceCodeInfo_Location_msg_init, arena); +} +UPB_INLINE google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_Location_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_SourceCodeInfo_Location* ret = google_protobuf_SourceCodeInfo_Location_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_Location_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_Location_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_SourceCodeInfo_Location* ret = google_protobuf_SourceCodeInfo_Location_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_Location_msg_init, extreg, options, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_SourceCodeInfo_Location_serialize(const google_protobuf_SourceCodeInfo_Location* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, &google_protobuf_SourceCodeInfo_Location_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_SourceCodeInfo_Location_serialize_ex(const google_protobuf_SourceCodeInfo_Location* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, &google_protobuf_SourceCodeInfo_Location_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_path(const google_protobuf_SourceCodeInfo_Location* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_path(const google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_span(const google_protobuf_SourceCodeInfo_Location* msg) { + _upb_array_detach(msg, UPB_SIZE(8, 16)); +} +UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_span(const google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(8, 16), len); +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} +UPB_INLINE upb_StringView google_protobuf_SourceCodeInfo_Location_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); +} +UPB_INLINE upb_StringView google_protobuf_SourceCodeInfo_Location_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + _upb_array_detach(msg, UPB_SIZE(28, 56)); +} +UPB_INLINE upb_StringView const* google_protobuf_SourceCodeInfo_Location_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); +} + +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_path(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); +} +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_path(google_protobuf_SourceCodeInfo_Location* msg, size_t len, upb_Arena* arena) { + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, 2, arena); +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_path(google_protobuf_SourceCodeInfo_Location* msg, int32_t val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), 2, &val, arena); +} +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_span(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 16), len); +} +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_span(google_protobuf_SourceCodeInfo_Location* msg, size_t len, upb_Arena* arena) { + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(8, 16), len, 2, arena); +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_span(google_protobuf_SourceCodeInfo_Location* msg, int32_t val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(8, 16), 2, &val, arena); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_leading_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView value) { + _upb_sethas(msg, 1); + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = value; +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_trailing_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView value) { + _upb_sethas(msg, 2); + *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView) = value; +} +UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_mutable_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); +} +UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_resize_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, size_t len, upb_Arena* arena) { + return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(3, 4), arena); +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, upb_StringView val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(3, 4), &val, arena); +} + +/* google.protobuf.GeneratedCodeInfo */ + +UPB_INLINE google_protobuf_GeneratedCodeInfo* google_protobuf_GeneratedCodeInfo_new(upb_Arena* arena) { + return (google_protobuf_GeneratedCodeInfo*)_upb_Message_New(&google_protobuf_GeneratedCodeInfo_msg_init, arena); +} +UPB_INLINE google_protobuf_GeneratedCodeInfo* google_protobuf_GeneratedCodeInfo_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_GeneratedCodeInfo* ret = google_protobuf_GeneratedCodeInfo_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_GeneratedCodeInfo* google_protobuf_GeneratedCodeInfo_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_GeneratedCodeInfo* ret = google_protobuf_GeneratedCodeInfo_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_msg_init, extreg, options, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_GeneratedCodeInfo_serialize(const google_protobuf_GeneratedCodeInfo* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_GeneratedCodeInfo_serialize_ex(const google_protobuf_GeneratedCodeInfo* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_has_annotation(const google_protobuf_GeneratedCodeInfo* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_clear_annotation(const google_protobuf_GeneratedCodeInfo* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE const google_protobuf_GeneratedCodeInfo_Annotation* const* google_protobuf_GeneratedCodeInfo_annotation(const google_protobuf_GeneratedCodeInfo* msg, size_t* len) { + return (const google_protobuf_GeneratedCodeInfo_Annotation* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); +} + +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_mutable_annotation(google_protobuf_GeneratedCodeInfo* msg, size_t* len) { + return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); +} +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_resize_annotation(google_protobuf_GeneratedCodeInfo* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); +} +UPB_INLINE struct google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_add_annotation(google_protobuf_GeneratedCodeInfo* msg, upb_Arena* arena) { + struct google_protobuf_GeneratedCodeInfo_Annotation* sub = (struct google_protobuf_GeneratedCodeInfo_Annotation*)_upb_Message_New(&google_protobuf_GeneratedCodeInfo_Annotation_msg_init, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); + if (!ok) return NULL; + return sub; +} + +/* google.protobuf.GeneratedCodeInfo.Annotation */ + +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_Annotation_new(upb_Arena* arena) { + return (google_protobuf_GeneratedCodeInfo_Annotation*)_upb_Message_New(&google_protobuf_GeneratedCodeInfo_Annotation_msg_init, arena); +} +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_Annotation_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_GeneratedCodeInfo_Annotation* ret = google_protobuf_GeneratedCodeInfo_Annotation_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_Annotation_msg_init, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_Annotation_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_GeneratedCodeInfo_Annotation* ret = google_protobuf_GeneratedCodeInfo_Annotation_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_Annotation_msg_init, extreg, options, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_GeneratedCodeInfo_Annotation_serialize(const google_protobuf_GeneratedCodeInfo_Annotation* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_Annotation_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_GeneratedCodeInfo_Annotation_serialize_ex(const google_protobuf_GeneratedCodeInfo_Annotation* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_Annotation_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_path(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + _upb_array_detach(msg, UPB_SIZE(16, 16)); +} +UPB_INLINE int32_t const* google_protobuf_GeneratedCodeInfo_Annotation_path(const google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t* len) { + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(16, 16), len); +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} +UPB_INLINE upb_StringView google_protobuf_GeneratedCodeInfo_Annotation_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_StringView); +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 2); +} +UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 3); +} +UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_semantic(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return _upb_hasbit(msg, 4); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_semantic(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = 0; + _upb_clearhas(msg, 4); +} +UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_semantic(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t); +} + +UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_mutable_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t* len) { + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 16), len); +} +UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_resize_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t len, upb_Arena* arena) { + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 16), len, 2, arena); +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_add_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, int32_t val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(16, 16), 2, &val, arena); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_source_file(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_StringView value) { + _upb_sethas(msg, 1); + *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_StringView) = value; +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_begin(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { + _upb_sethas(msg, 2); + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_end(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { + _upb_sethas(msg, 3); + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_semantic(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { + _upb_sethas(msg, 4); + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = value; +} + +extern const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout; + +/* Max size 32 is google.protobuf.FileOptions */ +/* Max size 64 is google.protobuf.FileOptions */ +#define _UPB_MAXOPT_SIZE UPB_SIZE(104, 192) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ */ + +/* + * Internal implementation details of the decoder that are shared between + * decode.c and decode_fast.c. + */ + +#ifndef UPB_INTERNAL_DECODE_H_ +#define UPB_INTERNAL_DECODE_H_ + + +#ifndef UPB_INTERNAL_ARENA_H_ +#define UPB_INTERNAL_ARENA_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct mem_block mem_block; + +struct upb_Arena { + _upb_ArenaHead head; + /* Stores cleanup metadata for this arena. + * - a pointer to the current cleanup counter. + * - a boolean indicating if there is an unowned initial block. */ + uintptr_t cleanup_metadata; + + /* Allocator to allocate arena blocks. We are responsible for freeing these + * when we are destroyed. */ + upb_alloc* block_alloc; + uint32_t last_size; + + /* When multiple arenas are fused together, each arena points to a parent + * arena (root points to itself). The root tracks how many live arenas + * reference it. */ + uint32_t refcount; /* Only used when a->parent == a */ + struct upb_Arena* parent; + + /* Linked list of blocks to free/cleanup. */ + mem_block *freelist, *freelist_tail; +}; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_INTERNAL_ARENA_H_ */ + +#include "third_party/utf8_range/utf8_range.h" + +// Must be last. + +#define DECODE_NOGROUP (uint32_t) - 1 + +typedef struct upb_Decoder { + const char* end; /* Can read up to 16 bytes slop beyond this. */ + const char* limit_ptr; /* = end + UPB_MIN(limit, 0) */ + upb_Message* unknown_msg; /* Used for preserving unknown data. */ + const char* unknown; /* Start of unknown data, preserve at buffer flip. */ + const upb_ExtensionRegistry* + extreg; /* For looking up extensions during the parse. */ + int limit; /* Submessage limit relative to end. */ + int depth; /* Tracks recursion depth to bound stack usage. */ + uint32_t end_group; /* field number of END_GROUP tag, else DECODE_NOGROUP */ + uint16_t options; + bool missing_required; + char patch[32]; + upb_Arena arena; + jmp_buf err; + +#ifndef NDEBUG + const char* debug_tagstart; + const char* debug_valstart; +#endif +} upb_Decoder; + +/* Error function that will abort decoding with longjmp(). We can't declare this + * UPB_NORETURN, even though it is appropriate, because if we do then compilers + * will "helpfully" refuse to tailcall to it + * (see: https://stackoverflow.com/a/55657013), which will defeat a major goal + * of our optimizations. That is also why we must declare it in a separate file, + * otherwise the compiler will see that it calls longjmp() and deduce that it is + * noreturn. */ +const char* _upb_FastDecoder_ErrorJmp(upb_Decoder* d, int status); + +extern const uint8_t upb_utf8_offsets[]; + +UPB_INLINE +bool _upb_Decoder_VerifyUtf8Inline(const char* ptr, int len) { + const char* end = ptr + len; + + // Check 8 bytes at a time for any non-ASCII char. + while (end - ptr >= 8) { + uint64_t data; + memcpy(&data, ptr, 8); + if (data & 0x8080808080808080) goto non_ascii; + ptr += 8; + } + + // Check one byte at a time for non-ASCII. + while (ptr < end) { + if (*ptr & 0x80) goto non_ascii; + ptr++; + } + + return true; + +non_ascii: + return utf8_range2((const unsigned char*)ptr, end - ptr) == 0; +} + +const char* _upb_Decoder_CheckRequired(upb_Decoder* d, const char* ptr, + const upb_Message* msg, + const upb_MiniTable* l); + +/* x86-64 pointers always have the high 16 bits matching. So we can shift + * left 8 and right 8 without loss of information. */ +UPB_INLINE intptr_t decode_totable(const upb_MiniTable* tablep) { + return ((intptr_t)tablep << 8) | tablep->table_mask; +} + +UPB_INLINE const upb_MiniTable* decode_totablep(intptr_t table) { + return (const upb_MiniTable*)(table >> 8); +} + +UPB_INLINE +const char* _upb_Decoder_IsDoneFallbackInline(upb_Decoder* d, const char* ptr, + int overrun, int* status) { + if (overrun < d->limit) { + /* Need to copy remaining data into patch buffer. */ + UPB_ASSERT(overrun < 16); + if (d->unknown) { + if (!_upb_Message_AddUnknown(d->unknown_msg, d->unknown, ptr - d->unknown, + &d->arena)) { + *status = kUpb_DecodeStatus_OutOfMemory; + return NULL; + } + d->unknown = &d->patch[0] + overrun; + } + memset(d->patch + 16, 0, 16); + memcpy(d->patch, d->end, 16); + ptr = &d->patch[0] + overrun; + d->end = &d->patch[16]; + d->limit -= 16; + d->limit_ptr = d->end + d->limit; + d->options &= ~kUpb_DecodeOption_AliasString; + UPB_ASSERT(ptr < d->limit_ptr); + return ptr; + } else { + *status = kUpb_DecodeStatus_Malformed; + return NULL; + } +} + +const char* _upb_Decoder_IsDoneFallback(upb_Decoder* d, const char* ptr, + int overrun); + +UPB_INLINE +bool _upb_Decoder_IsDone(upb_Decoder* d, const char** ptr) { + int overrun = *ptr - d->end; + if (UPB_LIKELY(*ptr < d->limit_ptr)) { + return false; + } else if (UPB_LIKELY(overrun == d->limit)) { + return true; + } else { + *ptr = _upb_Decoder_IsDoneFallback(d, *ptr, overrun); + return false; + } +} + +#if UPB_FASTTABLE +UPB_INLINE +const char* _upb_FastDecoder_TagDispatch(upb_Decoder* d, const char* ptr, + upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t tag) { + const upb_MiniTable* table_p = decode_totablep(table); + uint8_t mask = table; + uint64_t data; + size_t idx = tag & mask; + UPB_ASSUME((idx & 7) == 0); + idx >>= 3; + data = table_p->fasttable[idx].field_data ^ tag; + UPB_MUSTTAIL return table_p->fasttable[idx].field_parser(d, ptr, msg, table, + hasbits, data); +} +#endif + +UPB_INLINE uint32_t _upb_FastDecoder_LoadTag(const char* ptr) { + uint16_t tag; + memcpy(&tag, ptr, 2); + return tag; +} + +UPB_INLINE void _upb_Decoder_CheckLimit(upb_Decoder* d) { + UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); +} + +UPB_INLINE int _upb_Decoder_PushLimit(upb_Decoder* d, const char* ptr, + int size) { + int limit = size + (int)(ptr - d->end); + int delta = d->limit - limit; + _upb_Decoder_CheckLimit(d); + d->limit = limit; + d->limit_ptr = d->end + UPB_MIN(0, limit); + _upb_Decoder_CheckLimit(d); + return delta; +} + +UPB_INLINE void _upb_Decoder_PopLimit(upb_Decoder* d, const char* ptr, + int saved_delta) { + UPB_ASSERT(ptr - d->end == d->limit); + _upb_Decoder_CheckLimit(d); + d->limit += saved_delta; + d->limit_ptr = d->end + UPB_MIN(0, d->limit); + _upb_Decoder_CheckLimit(d); +} + + +#endif /* UPB_INTERNAL_DECODE_H_ */ + +#ifndef UPB_JSON_DECODE_H_ +#define UPB_JSON_DECODE_H_ + + +#ifndef UPB_REFLECTION_DEF_H_ +#define UPB_REFLECTION_DEF_H_ + + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_DEF_POOL_H_ +#define UPB_REFLECTION_DEF_POOL_H_ + + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +// Declarations common to all public def types. + +#ifndef UPB_REFLECTION_COMMON_H_ +#define UPB_REFLECTION_COMMON_H_ + + +typedef enum { kUpb_Syntax_Proto2 = 2, kUpb_Syntax_Proto3 = 3 } upb_Syntax; + +// Forward declarations for circular references. +typedef struct upb_DefPool upb_DefPool; +typedef struct upb_EnumDef upb_EnumDef; +typedef struct upb_EnumValueDef upb_EnumValueDef; +typedef struct upb_ExtensionRange upb_ExtensionRange; +typedef struct upb_FieldDef upb_FieldDef; +typedef struct upb_FileDef upb_FileDef; +typedef struct upb_MessageDef upb_MessageDef; +typedef struct upb_MethodDef upb_MethodDef; +typedef struct upb_OneofDef upb_OneofDef; +typedef struct upb_ServiceDef upb_ServiceDef; + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +typedef struct upb_DefBuilder upb_DefBuilder; + +#endif /* UPB_REFLECTION_COMMON_H_ */ + +#ifndef UPB_REFLECTION_DEF_TYPE_H_ +#define UPB_REFLECTION_DEF_TYPE_H_ + + +// Must be last. + +// Inside a symtab we store tagged pointers to specific def types. +typedef enum { + UPB_DEFTYPE_MASK = 7, + + // Only inside symtab table. + UPB_DEFTYPE_EXT = 0, + UPB_DEFTYPE_MSG = 1, + UPB_DEFTYPE_ENUM = 2, + UPB_DEFTYPE_ENUMVAL = 3, + UPB_DEFTYPE_SERVICE = 4, + + // Only inside message table. + UPB_DEFTYPE_FIELD = 0, + UPB_DEFTYPE_ONEOF = 1, + UPB_DEFTYPE_FIELD_JSONNAME = 2, +} upb_deftype_t; + +#ifdef __cplusplus +extern "C" { +#endif + +// Our 3-bit pointer tagging requires all pointers to be multiples of 8. +// The arena will always yield 8-byte-aligned addresses, however we put +// the defs into arrays. For each element in the array to be 8-byte-aligned, +// the sizes of each def type must also be a multiple of 8. +// +// If any of these asserts fail, we need to add or remove padding on 32-bit +// machines (64-bit machines will have 8-byte alignment already due to +// pointers, which all of these structs have). +UPB_INLINE void _upb_DefType_CheckPadding(size_t size) { + UPB_ASSERT((size & UPB_DEFTYPE_MASK) == 0); +} + +upb_deftype_t _upb_DefType_Type(upb_value v); + +upb_value _upb_DefType_Pack(const void* ptr, upb_deftype_t type); + +const void* _upb_DefType_Unpack(upb_value v, upb_deftype_t type); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_DEF_TYPE_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +void upb_DefPool_Free(upb_DefPool* s); + +upb_DefPool* upb_DefPool_New(void); + +const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, + const char* sym); + +const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( + const upb_DefPool* s, const char* sym, size_t len); + +const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, + const char* sym); + +const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, + const char* sym); + +const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, + const char* name); + +const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, + const char* name, + size_t len); + +const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( + const upb_DefPool* s, const char* name, size_t size); + +const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, + const char* sym); + +const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, + const char* name); + +const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( + const upb_DefPool* s, const char* name, size_t size); + +const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, + const char* name); + +const upb_FileDef* upb_DefPool_AddFile( + upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, + upb_Status* status); + +const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, + const upb_MessageDef* m, + int32_t fieldnum); + +const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( + const upb_DefPool* s); + +const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, + const upb_MessageDef* m, + size_t* count); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s); +size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s); +upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s); +const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable( + const upb_DefPool* s, const upb_MiniTable_Extension* ext); + +bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTable_Extension* ext, + upb_FieldDef* f); +bool _upb_DefPool_InsertSym(upb_DefPool* s, upb_StringView sym, upb_value v, + upb_Status* status); +bool _upb_DefPool_LookupSym(const upb_DefPool* s, const char* sym, size_t size, + upb_value* v); + +void** _upb_DefPool_ScratchData(const upb_DefPool* s); +size_t* _upb_DefPool_ScratchSize(const upb_DefPool* s); + +// For generated code only: loads a generated descriptor. +typedef struct _upb_DefPool_Init { + struct _upb_DefPool_Init** deps; // Dependencies of this file. + const upb_MiniTable_File* layout; + const char* filename; + upb_StringView descriptor; // Serialized descriptor. +} _upb_DefPool_Init; + +bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init); + +// Should only be directly called by tests. This variant lets us suppress +// the use of compiled-in tables, forcing a rebuild of the tables at runtime. +bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, + bool rebuild_minitable); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_DEF_POOL_H_ */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_ENUM_DEF_H_ +#define UPB_REFLECTION_ENUM_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num); +const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e); +int32_t upb_EnumDef_Default(const upb_EnumDef* e); +const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e); +const upb_EnumValueDef* upb_EnumDef_FindValueByName(const upb_EnumDef* e, + const char* name); +const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( + const upb_EnumDef* e, const char* name, size_t size); +const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* e, + int32_t num); +const char* upb_EnumDef_FullName(const upb_EnumDef* e); +bool upb_EnumDef_HasOptions(const upb_EnumDef* e); + +// Creates a mini descriptor string for an enum, returns true on success. +bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, + upb_StringView* out); + +const char* upb_EnumDef_Name(const upb_EnumDef* e); +const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e); +const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i); +int upb_EnumDef_ValueCount(const upb_EnumDef* e); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i); +bool _upb_EnumDef_Insert(upb_EnumDef* e, upb_EnumValueDef* v, upb_Arena* a); +const upb_MiniTable_Enum* _upb_EnumDef_MiniTable(const upb_EnumDef* e); + +// Allocate and initialize an array of |n| enum defs. +upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, + const google_protobuf_EnumDescriptorProto* const* protos, + const upb_MessageDef* containing_type); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ENUM_DEF_H_ */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_ENUM_VALUE_DEF_H_ +#define UPB_REFLECTION_ENUM_VALUE_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* v); +const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* v); +bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* v); +uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v); +const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v); +int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v); +const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( + const upb_EnumValueDef* v); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i); + +// Allocate and initialize an array of |n| enum value defs owned by |e|. +upb_EnumValueDef* _upb_EnumValueDefs_New( + upb_DefBuilder* ctx, const char* prefix, int n, + const google_protobuf_EnumValueDescriptorProto* const* protos, upb_EnumDef* e, + bool* is_sorted); + +const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v, + int n, upb_Arena* a); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ENUM_VALUE_DEF_H_ */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_EXTENSION_RANGE_H_ +#define UPB_REFLECTION_EXTENSION_RANGE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* r); +int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r); + +bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r); +const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( + const upb_ExtensionRange* r); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_ExtensionRange* _upb_ExtensionRange_At(const upb_ExtensionRange* r, int i); + +// Allocate and initialize an array of |n| extension ranges owned by |m|. +upb_ExtensionRange* _upb_ExtensionRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_DescriptorProto_ExtensionRange* const* protos, + const upb_MessageDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_EXTENSION_RANGE_H_ */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_FIELD_DEF_H_ +#define UPB_REFLECTION_FIELD_DEF_H_ + + +// Must be last. + +// Maximum field number allowed for FieldDefs. +// This is an inherent limit of the protobuf wire format. +#define kUpb_MaxFieldNumber ((1 << 29) - 1) + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f); +const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f); +upb_CType upb_FieldDef_CType(const upb_FieldDef* f); +const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f); +const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f); +const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f); +const char* upb_FieldDef_FullName(const upb_FieldDef* f); +bool upb_FieldDef_HasDefault(const upb_FieldDef* f); +bool upb_FieldDef_HasJsonName(const upb_FieldDef* f); +bool upb_FieldDef_HasOptions(const upb_FieldDef* f); +bool upb_FieldDef_HasPresence(const upb_FieldDef* f); +bool upb_FieldDef_HasSubDef(const upb_FieldDef* f); +uint32_t upb_FieldDef_Index(const upb_FieldDef* f); +bool upb_FieldDef_IsExtension(const upb_FieldDef* f); +bool upb_FieldDef_IsMap(const upb_FieldDef* f); +bool upb_FieldDef_IsOptional(const upb_FieldDef* f); +bool upb_FieldDef_IsPacked(const upb_FieldDef* f); +bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f); +bool upb_FieldDef_IsRepeated(const upb_FieldDef* f); +bool upb_FieldDef_IsRequired(const upb_FieldDef* f); +bool upb_FieldDef_IsString(const upb_FieldDef* f); +bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f); +const char* upb_FieldDef_JsonName(const upb_FieldDef* f); +upb_Label upb_FieldDef_Label(const upb_FieldDef* f); +const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f); + +// Creates a mini descriptor string for a field, returns true on success. +bool upb_FieldDef_MiniDescriptorEncode(const upb_FieldDef* f, upb_Arena* a, + upb_StringView* out); + +const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f); +const char* upb_FieldDef_Name(const upb_FieldDef* f); +uint32_t upb_FieldDef_Number(const upb_FieldDef* f); +const google_protobuf_FieldOptions* upb_FieldDef_Options(const upb_FieldDef* f); +const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f); +upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i); + +const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable( + const upb_FieldDef* f); +bool _upb_FieldDef_IsClosedEnum(const upb_FieldDef* f); +bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f); +int _upb_FieldDef_LayoutIndex(const upb_FieldDef* f); +uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f); +void _upb_FieldDef_Resolve(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f); + +// Allocate and initialize an array of |n| field defs. +upb_FieldDef* _upb_FieldDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_FieldDescriptorProto* const* protos, const char* prefix, + upb_MessageDef* m, bool* is_sorted); + +// Allocate and return a list of pointers to the |n| field defs in |ff|, +// sorted by field number. +const upb_FieldDef** _upb_FieldDefs_Sorted(const upb_FieldDef* f, int n, + upb_Arena* a); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_FIELD_DEF_H_ */ -UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_new(upb_Arena* arena) { - return (google_protobuf_SourceCodeInfo*)_upb_Message_New(&google_protobuf_SourceCodeInfo_msginit, arena); -} -UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_parse(const char* buf, size_t size, upb_Arena* arena) { - google_protobuf_SourceCodeInfo* ret = google_protobuf_SourceCodeInfo_new(arena); - if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { - return NULL; - } - return ret; -} -UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_parse_ex(const char* buf, size_t size, - const upb_ExtensionRegistry* extreg, - int options, upb_Arena* arena) { - google_protobuf_SourceCodeInfo* ret = google_protobuf_SourceCodeInfo_new(arena); - if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_msginit, extreg, options, arena) != - kUpb_DecodeStatus_Ok) { - return NULL; - } - return ret; -} -UPB_INLINE char* google_protobuf_SourceCodeInfo_serialize(const google_protobuf_SourceCodeInfo* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_SourceCodeInfo_msginit, 0, arena, len); -} -UPB_INLINE char* google_protobuf_SourceCodeInfo_serialize_ex(const google_protobuf_SourceCodeInfo* msg, int options, - upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_SourceCodeInfo_msginit, options, arena, len); -} -UPB_INLINE bool google_protobuf_SourceCodeInfo_has_location(const google_protobuf_SourceCodeInfo* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); -} -UPB_INLINE const google_protobuf_SourceCodeInfo_Location* const* google_protobuf_SourceCodeInfo_location(const google_protobuf_SourceCodeInfo* msg, size_t* len) { - return (const google_protobuf_SourceCodeInfo_Location* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); -} +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" -UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_mutable_location(google_protobuf_SourceCodeInfo* msg, size_t* len) { - return (google_protobuf_SourceCodeInfo_Location**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); -} -UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_resize_location(google_protobuf_SourceCodeInfo* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_SourceCodeInfo_Location**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); -} -UPB_INLINE struct google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_add_location(google_protobuf_SourceCodeInfo* msg, upb_Arena* arena) { - struct google_protobuf_SourceCodeInfo_Location* sub = (struct google_protobuf_SourceCodeInfo_Location*)_upb_Message_New(&google_protobuf_SourceCodeInfo_Location_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); - if (!ok) return NULL; - return sub; -} +#ifndef UPB_REFLECTION_FILE_DEF_H_ +#define UPB_REFLECTION_FILE_DEF_H_ -/* google.protobuf.SourceCodeInfo.Location */ -UPB_INLINE google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_Location_new(upb_Arena* arena) { - return (google_protobuf_SourceCodeInfo_Location*)_upb_Message_New(&google_protobuf_SourceCodeInfo_Location_msginit, arena); -} -UPB_INLINE google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_Location_parse(const char* buf, size_t size, upb_Arena* arena) { - google_protobuf_SourceCodeInfo_Location* ret = google_protobuf_SourceCodeInfo_Location_new(arena); - if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_Location_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { - return NULL; - } - return ret; -} -UPB_INLINE google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_Location_parse_ex(const char* buf, size_t size, - const upb_ExtensionRegistry* extreg, - int options, upb_Arena* arena) { - google_protobuf_SourceCodeInfo_Location* ret = google_protobuf_SourceCodeInfo_Location_new(arena); - if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_Location_msginit, extreg, options, arena) != - kUpb_DecodeStatus_Ok) { - return NULL; - } - return ret; -} -UPB_INLINE char* google_protobuf_SourceCodeInfo_Location_serialize(const google_protobuf_SourceCodeInfo_Location* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_SourceCodeInfo_Location_msginit, 0, arena, len); -} -UPB_INLINE char* google_protobuf_SourceCodeInfo_Location_serialize_ex(const google_protobuf_SourceCodeInfo_Location* msg, int options, - upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_SourceCodeInfo_Location_msginit, options, arena, len); -} -UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_path(const google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { - return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); -} -UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_span(const google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { - return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); -} -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { - return _upb_hasbit(msg, 1); -} -UPB_INLINE upb_StringView google_protobuf_SourceCodeInfo_Location_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); -} -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { - return _upb_hasbit(msg, 2); -} -UPB_INLINE upb_StringView google_protobuf_SourceCodeInfo_Location_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); -} -UPB_INLINE upb_StringView const* google_protobuf_SourceCodeInfo_Location_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { - return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); -} +// Must be last. -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_path(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); -} -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_path(google_protobuf_SourceCodeInfo_Location* msg, size_t len, upb_Arena* arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, 2, arena); -} -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_path(google_protobuf_SourceCodeInfo_Location* msg, int32_t val, upb_Arena* arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), 2, &val, arena); -} -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_span(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); -} -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_span(google_protobuf_SourceCodeInfo_Location* msg, size_t len, upb_Arena* arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, 2, arena); -} -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_span(google_protobuf_SourceCodeInfo_Location* msg, int32_t val, upb_Arena* arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), 2, &val, arena); -} -UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_leading_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_trailing_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = value; -} -UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_mutable_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { - return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); -} -UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_resize_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, size_t len, upb_Arena* arena) { - return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(3, 4), arena); -} -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, upb_StringView val, upb_Arena* arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(3, 4), &val, arena); -} +#ifdef __cplusplus +extern "C" { +#endif -/* google.protobuf.GeneratedCodeInfo */ +const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i); +int upb_FileDef_DependencyCount(const upb_FileDef* f); +bool upb_FileDef_HasOptions(const upb_FileDef* f); +const char* upb_FileDef_Name(const upb_FileDef* f); +const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f); +const char* upb_FileDef_Package(const upb_FileDef* f); +const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f); -UPB_INLINE google_protobuf_GeneratedCodeInfo* google_protobuf_GeneratedCodeInfo_new(upb_Arena* arena) { - return (google_protobuf_GeneratedCodeInfo*)_upb_Message_New(&google_protobuf_GeneratedCodeInfo_msginit, arena); -} -UPB_INLINE google_protobuf_GeneratedCodeInfo* google_protobuf_GeneratedCodeInfo_parse(const char* buf, size_t size, upb_Arena* arena) { - google_protobuf_GeneratedCodeInfo* ret = google_protobuf_GeneratedCodeInfo_new(arena); - if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { - return NULL; - } - return ret; -} -UPB_INLINE google_protobuf_GeneratedCodeInfo* google_protobuf_GeneratedCodeInfo_parse_ex(const char* buf, size_t size, - const upb_ExtensionRegistry* extreg, - int options, upb_Arena* arena) { - google_protobuf_GeneratedCodeInfo* ret = google_protobuf_GeneratedCodeInfo_new(arena); - if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_msginit, extreg, options, arena) != - kUpb_DecodeStatus_Ok) { - return NULL; - } - return ret; -} -UPB_INLINE char* google_protobuf_GeneratedCodeInfo_serialize(const google_protobuf_GeneratedCodeInfo* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_msginit, 0, arena, len); -} -UPB_INLINE char* google_protobuf_GeneratedCodeInfo_serialize_ex(const google_protobuf_GeneratedCodeInfo* msg, int options, - upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_msginit, options, arena, len); -} -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_has_annotation(const google_protobuf_GeneratedCodeInfo* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); -} -UPB_INLINE const google_protobuf_GeneratedCodeInfo_Annotation* const* google_protobuf_GeneratedCodeInfo_annotation(const google_protobuf_GeneratedCodeInfo* msg, size_t* len) { - return (const google_protobuf_GeneratedCodeInfo_Annotation* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); -} +const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i); +int upb_FileDef_PublicDependencyCount(const upb_FileDef* f); -UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_mutable_annotation(google_protobuf_GeneratedCodeInfo* msg, size_t* len) { - return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); -} -UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_resize_annotation(google_protobuf_GeneratedCodeInfo* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); -} -UPB_INLINE struct google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_add_annotation(google_protobuf_GeneratedCodeInfo* msg, upb_Arena* arena) { - struct google_protobuf_GeneratedCodeInfo_Annotation* sub = (struct google_protobuf_GeneratedCodeInfo_Annotation*)_upb_Message_New(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); - if (!ok) return NULL; - return sub; -} +const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i); +int upb_FileDef_ServiceCount(const upb_FileDef* f); -/* google.protobuf.GeneratedCodeInfo.Annotation */ +upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f); -UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_Annotation_new(upb_Arena* arena) { - return (google_protobuf_GeneratedCodeInfo_Annotation*)_upb_Message_New(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena); -} -UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_Annotation_parse(const char* buf, size_t size, upb_Arena* arena) { - google_protobuf_GeneratedCodeInfo_Annotation* ret = google_protobuf_GeneratedCodeInfo_Annotation_new(arena); - if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) { - return NULL; - } - return ret; -} -UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_Annotation_parse_ex(const char* buf, size_t size, - const upb_ExtensionRegistry* extreg, - int options, upb_Arena* arena) { - google_protobuf_GeneratedCodeInfo_Annotation* ret = google_protobuf_GeneratedCodeInfo_Annotation_new(arena); - if (!ret) return NULL; - if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, extreg, options, arena) != - kUpb_DecodeStatus_Ok) { - return NULL; - } - return ret; -} -UPB_INLINE char* google_protobuf_GeneratedCodeInfo_Annotation_serialize(const google_protobuf_GeneratedCodeInfo_Annotation* msg, upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, 0, arena, len); -} -UPB_INLINE char* google_protobuf_GeneratedCodeInfo_Annotation_serialize_ex(const google_protobuf_GeneratedCodeInfo_Annotation* msg, int options, - upb_Arena* arena, size_t* len) { - return upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, options, arena, len); -} -UPB_INLINE int32_t const* google_protobuf_GeneratedCodeInfo_Annotation_path(const google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t* len) { - return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(20, 32), len); -} -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { - return _upb_hasbit(msg, 1); -} -UPB_INLINE upb_StringView google_protobuf_GeneratedCodeInfo_Annotation_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 16), upb_StringView); -} -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { - return _upb_hasbit(msg, 2); -} -UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); -} -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { - return _upb_hasbit(msg, 3); -} -UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); -} +const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i); +int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f); -UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_mutable_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t* len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 32), len); -} -UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_resize_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t len, upb_Arena* arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 32), len, 2, arena); -} -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_add_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, int32_t val, upb_Arena* arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 32), 2, &val, arena); -} -UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_source_file(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_StringView value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(12, 16), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_begin(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; -} -UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_end(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; -} +const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i); +int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f); -extern const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout; +const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i); +int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f); -/* Max size 32 is google.protobuf.FileOptions */ -/* Max size 64 is google.protobuf.FileOptions */ -#define _UPB_MAXOPT_SIZE UPB_SIZE(104, 192) +const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i); +int upb_FileDef_WeakDependencyCount(const upb_FileDef* f); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +const upb_MiniTable_Extension* _upb_FileDef_ExtensionMiniTable( + const upb_FileDef* f, int i); +const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f); +const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f); + +// upb_FileDef_Package() returns "" if f->package is NULL, this does not. +const char* _upb_FileDef_RawPackage(const upb_FileDef* f); + +void _upb_FileDef_Create(upb_DefBuilder* ctx, + const google_protobuf_FileDescriptorProto* file_proto); #ifdef __cplusplus -} /* extern "C" */ +} /* extern "C" */ #endif -#endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ */ +#endif /* UPB_REFLECTION_FILE_DEF_H_ */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_MESSAGE_DEF_H_ +#define UPB_REFLECTION_MESSAGE_DEF_H_ -/** upb/def.h ************************************************************/ -#ifndef UPB_DEF_H_ -#define UPB_DEF_H_ +// Must be last. -/* Must be last. */ +// Well-known field tag numbers for map-entry messages. +#define kUpb_MapEntry_KeyFieldNumber 1 +#define kUpb_MapEntry_ValueFieldNumber 2 -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ +// Well-known field tag numbers for Any messages. +#define kUpb_Any_TypeFieldNumber 1 +#define kUpb_Any_ValueFieldNumber 2 -struct upb_EnumDef; -typedef struct upb_EnumDef upb_EnumDef; -struct upb_EnumValueDef; -typedef struct upb_EnumValueDef upb_EnumValueDef; -struct upb_ExtensionRange; -typedef struct upb_ExtensionRange upb_ExtensionRange; -struct upb_FieldDef; -typedef struct upb_FieldDef upb_FieldDef; -struct upb_FileDef; -typedef struct upb_FileDef upb_FileDef; -struct upb_MethodDef; -typedef struct upb_MethodDef upb_MethodDef; -struct upb_MessageDef; -typedef struct upb_MessageDef upb_MessageDef; -struct upb_OneofDef; -typedef struct upb_OneofDef upb_OneofDef; -struct upb_ServiceDef; -typedef struct upb_ServiceDef upb_ServiceDef; -struct upb_streamdef; -typedef struct upb_streamdef upb_streamdef; -struct upb_DefPool; -typedef struct upb_DefPool upb_DefPool; +// Well-known field tag numbers for duration messages. +#define kUpb_Duration_SecondsFieldNumber 1 +#define kUpb_Duration_NanosFieldNumber 2 -typedef enum { kUpb_Syntax_Proto2 = 2, kUpb_Syntax_Proto3 = 3 } upb_Syntax; +// Well-known field tag numbers for timestamp messages. +#define kUpb_Timestamp_SecondsFieldNumber 1 +#define kUpb_Timestamp_NanosFieldNumber 2 -/* All the different kind of well known type messages. For simplicity of check, - * number wrappers and string wrappers are grouped together. Make sure the - * order and merber of these groups are not changed. - */ +// All the different kind of well known type messages. For simplicity of check, +// number wrappers and string wrappers are grouped together. Make sure the +// order and number of these groups are not changed. typedef enum { kUpb_WellKnown_Unspecified, kUpb_WellKnown_Any, kUpb_WellKnown_FieldMask, kUpb_WellKnown_Duration, kUpb_WellKnown_Timestamp, - /* number wrappers */ + + // number wrappers kUpb_WellKnown_DoubleValue, kUpb_WellKnown_FloatValue, kUpb_WellKnown_Int64Value, kUpb_WellKnown_UInt64Value, kUpb_WellKnown_Int32Value, kUpb_WellKnown_UInt32Value, - /* string wrappers */ + + // string wrappers kUpb_WellKnown_StringValue, kUpb_WellKnown_BytesValue, kUpb_WellKnown_BoolValue, kUpb_WellKnown_Value, kUpb_WellKnown_ListValue, - kUpb_WellKnown_Struct + kUpb_WellKnown_Struct, } upb_WellKnown; -/* upb_FieldDef ***************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif -/* Maximum field number allowed for FieldDefs. This is an inherent limit of the - * protobuf wire format. */ -#define kUpb_MaxFieldNumber ((1 << 29) - 1) +const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m); -const google_protobuf_FieldOptions* upb_FieldDef_Options(const upb_FieldDef* f); -bool upb_FieldDef_HasOptions(const upb_FieldDef* f); -const char* upb_FieldDef_FullName(const upb_FieldDef* f); -upb_CType upb_FieldDef_CType(const upb_FieldDef* f); -upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f); -upb_Label upb_FieldDef_Label(const upb_FieldDef* f); -uint32_t upb_FieldDef_Number(const upb_FieldDef* f); -const char* upb_FieldDef_Name(const upb_FieldDef* f); -const char* upb_FieldDef_JsonName(const upb_FieldDef* f); -bool upb_FieldDef_HasJsonName(const upb_FieldDef* f); -bool upb_FieldDef_IsExtension(const upb_FieldDef* f); -bool upb_FieldDef_IsPacked(const upb_FieldDef* f); -const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f); -const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f); -const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f); -const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f); -const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f); -uint32_t upb_FieldDef_Index(const upb_FieldDef* f); -bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f); -bool upb_FieldDef_IsString(const upb_FieldDef* f); -bool upb_FieldDef_IsRepeated(const upb_FieldDef* f); -bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f); -bool upb_FieldDef_IsMap(const upb_FieldDef* f); -bool upb_FieldDef_HasDefault(const upb_FieldDef* f); -bool upb_FieldDef_HasSubDef(const upb_FieldDef* f); -bool upb_FieldDef_HasPresence(const upb_FieldDef* f); -const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f); -const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f); -const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f); -const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable( - const upb_FieldDef* f); -bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f); +const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, + int i); +int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m); + +const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i); +int upb_MessageDef_FieldCount(const upb_MessageDef* m); + +const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m); + +// Returns a field by either JSON name or regular proto name. +const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( + const upb_MessageDef* m, const char* name, size_t size); +UPB_INLINE const upb_FieldDef* upb_MessageDef_FindByJsonName( + const upb_MessageDef* m, const char* name) { + return upb_MessageDef_FindByJsonNameWithSize(m, name, strlen(name)); +} + +// Lookup of either field or oneof by name. Returns whether either was found. +// If the return is true, then the found def will be set, and the non-found +// one set to NULL. +bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, + const char* name, size_t size, + const upb_FieldDef** f, + const upb_OneofDef** o); +UPB_INLINE bool upb_MessageDef_FindByName(const upb_MessageDef* m, + const char* name, + const upb_FieldDef** f, + const upb_OneofDef** o) { + return upb_MessageDef_FindByNameWithSize(m, name, strlen(name), f, o); +} + +const upb_FieldDef* upb_MessageDef_FindFieldByName(const upb_MessageDef* m, + const char* name); +const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size); +const upb_FieldDef* upb_MessageDef_FindFieldByNumber(const upb_MessageDef* m, + uint32_t i); +const upb_OneofDef* upb_MessageDef_FindOneofByName(const upb_MessageDef* m, + const char* name); +const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size); +const char* upb_MessageDef_FullName(const upb_MessageDef* m); +bool upb_MessageDef_HasOptions(const upb_MessageDef* m); +bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m); +bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m); + +// Creates a mini descriptor string for a message, returns true on success. +bool upb_MessageDef_MiniDescriptorEncode(const upb_MessageDef* m, upb_Arena* a, + upb_StringView* out); + +const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m); +const char* upb_MessageDef_Name(const upb_MessageDef* m); + +const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i); +const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, + int i); +const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, + int i); + +int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m); +int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m); +int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m); + +const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i); +int upb_MessageDef_OneofCount(const upb_MessageDef* m); + +const google_protobuf_MessageOptions* upb_MessageDef_Options(const upb_MessageDef* m); +upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m); +upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_MessageDef* _upb_MessageDef_At(const upb_MessageDef* m, int i); +bool _upb_MessageDef_InMessageSet(const upb_MessageDef* m); +bool _upb_MessageDef_Insert(upb_MessageDef* m, const char* name, size_t size, + upb_value v, upb_Arena* a); +void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m, + const upb_FieldDef* f); +bool _upb_MessageDef_IsValidExtensionNumber(const upb_MessageDef* m, int n); +void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx, + const upb_MessageDef* m); +void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m); + +// Allocate and initialize an array of |n| message defs. +upb_MessageDef* _upb_MessageDefs_New( + upb_DefBuilder* ctx, int n, const google_protobuf_DescriptorProto* const* protos, + const upb_MessageDef* containing_type); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_MESSAGE_DEF_H_ */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_METHOD_DEF_H_ +#define UPB_REFLECTION_METHOD_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m); +const char* upb_MethodDef_FullName(const upb_MethodDef* m); +bool upb_MethodDef_HasOptions(const upb_MethodDef* m); +int upb_MethodDef_Index(const upb_MethodDef* m); +const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m); +const char* upb_MethodDef_Name(const upb_MethodDef* m); +const google_protobuf_MethodOptions* upb_MethodDef_Options(const upb_MethodDef* m); +const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m); +bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m); +const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_MethodDef* _upb_MethodDef_At(const upb_MethodDef* m, int i); + +// Allocate and initialize an array of |n| method defs owned by |s|. +upb_MethodDef* _upb_MethodDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_MethodDescriptorProto* const* protos, upb_ServiceDef* s); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_METHOD_DEF_H_ */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_ONEOF_DEF_H_ +#define UPB_REFLECTION_ONEOF_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o); +const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i); +int upb_OneofDef_FieldCount(const upb_OneofDef* o); +const char* upb_OneofDef_FullName(const upb_OneofDef* o); +bool upb_OneofDef_HasOptions(const upb_OneofDef* o); +uint32_t upb_OneofDef_Index(const upb_OneofDef* o); +bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o); +const upb_FieldDef* upb_OneofDef_LookupName(const upb_OneofDef* o, + const char* name); +const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, + const char* name, + size_t size); +const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, + uint32_t num); +const char* upb_OneofDef_Name(const upb_OneofDef* o); +int upb_OneofDef_numfields(const upb_OneofDef* o); +const google_protobuf_OneofOptions* upb_OneofDef_Options(const upb_OneofDef* o); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_OneofDef* _upb_OneofDef_At(const upb_OneofDef* o, int i); +bool _upb_OneofDef_Insert(upb_OneofDef* o, const upb_FieldDef* f, + const char* name, size_t size, upb_Arena* a); + +// Allocate and initialize an array of |n| oneof defs owned by |m|. +upb_OneofDef* _upb_OneofDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_OneofDescriptorProto* const* protos, upb_MessageDef* m); + +size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ONEOF_DEF_H_ */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_SERVICE_DEF_H_ +#define UPB_REFLECTION_SERVICE_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s); +const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, + const char* name); +const char* upb_ServiceDef_FullName(const upb_ServiceDef* s); +bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s); +int upb_ServiceDef_Index(const upb_ServiceDef* s); +const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i); +int upb_ServiceDef_MethodCount(const upb_ServiceDef* s); +const char* upb_ServiceDef_Name(const upb_ServiceDef* s); +const google_protobuf_ServiceOptions* upb_ServiceDef_Options(const upb_ServiceDef* s); + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int i); + +// Allocate and initialize an array of |n| service defs. +upb_ServiceDef* _upb_ServiceDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_ServiceDescriptorProto* const* protos); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_SERVICE_DEF_H_ */ + +#endif /* UPB_REFLECTION_DEF_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +enum { upb_JsonDecode_IgnoreUnknown = 1 }; + +bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, + const upb_MessageDef* m, const upb_DefPool* symtab, + int options, upb_Arena* arena, upb_Status* status); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_JSONDECODE_H_ */ + +#ifndef UPB_INTERNAL_UNICODE_H_ +#define UPB_INTERNAL_UNICODE_H_ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Returns true iff a codepoint is the value for a high surrogate. +UPB_INLINE bool upb_Unicode_IsHigh(uint32_t cp) { + return (cp >= 0xd800 && cp <= 0xdbff); +} + +// Returns true iff a codepoint is the value for a low surrogate. +UPB_INLINE bool upb_Unicode_IsLow(uint32_t cp) { + return (cp >= 0xdc00 && cp <= 0xdfff); +} + +// Returns the high 16-bit surrogate value for a supplementary codepoint. +// Does not sanity-check the input. +UPB_INLINE uint16_t upb_Unicode_ToHigh(uint32_t cp) { + return (cp >> 10) + 0xd7c0; +} + +// Returns the low 16-bit surrogate value for a supplementary codepoint. +// Does not sanity-check the input. +UPB_INLINE uint16_t upb_Unicode_ToLow(uint32_t cp) { + return (cp & 0x3ff) | 0xdc00; +} + +// Returns the 32-bit value corresponding to a pair of 16-bit surrogates. +// Does not sanity-check the input. +UPB_INLINE uint32_t upb_Unicode_FromPair(uint32_t high, uint32_t low) { + return ((high & 0x3ff) << 10) + (low & 0x3ff) + 0x10000; +} + +// Outputs a codepoint as UTF8. +// Returns the number of bytes written (1-4 on success, 0 on error). +// Does not sanity-check the input. Specifically does not check for surrogates. +int upb_Unicode_ToUTF8(uint32_t cp, char* out); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_INTERNAL_UNICODE_H_ */ + +#ifndef UPB_REFLECTION_MESSAGE_H_ +#define UPB_REFLECTION_MESSAGE_H_ -/* upb_OneofDef ***************************************************************/ -const google_protobuf_OneofOptions* upb_OneofDef_Options(const upb_OneofDef* o); -bool upb_OneofDef_HasOptions(const upb_OneofDef* o); -const char* upb_OneofDef_Name(const upb_OneofDef* o); -const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o); -uint32_t upb_OneofDef_Index(const upb_OneofDef* o); -bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o); -int upb_OneofDef_FieldCount(const upb_OneofDef* o); -const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i); +// Must be last. -/* Oneof lookups: - * - ntof: look up a field by name. - * - ntofz: look up a field by name (as a null-terminated string). - * - itof: look up a field by number. */ -const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, - const char* name, - size_t length); -UPB_INLINE const upb_FieldDef* upb_OneofDef_LookupName(const upb_OneofDef* o, - const char* name) { - return upb_OneofDef_LookupNameWithSize(o, name, strlen(name)); -} -const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, - uint32_t num); +#ifdef __cplusplus +extern "C" { +#endif -/* upb_MessageDef *************************************************************/ +upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f); -/* Well-known field tag numbers for map-entry messages. */ -#define kUpb_MapEntry_KeyFieldNumber 1 -#define kUpb_MapEntry_ValueFieldNumber 2 +/* Creates a new message of the given type in the given arena. */ +upb_Message* upb_Message_New(const upb_MessageDef* m, upb_Arena* a); -/* Well-known field tag numbers for Any messages. */ -#define kUpb_Any_TypeFieldNumber 1 -#define kUpb_Any_ValueFieldNumber 2 +/* Returns the value associated with this field. */ +upb_MessageValue upb_Message_Get(const upb_Message* msg, const upb_FieldDef* f); -/* Well-known field tag numbers for timestamp messages. */ -#define kUpb_Duration_SecondsFieldNumber 1 -#define kUpb_Duration_NanosFieldNumber 2 +/* Returns a mutable pointer to a map, array, or submessage value. If the given + * arena is non-NULL this will construct a new object if it was not previously + * present. May not be called for primitive fields. */ +upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, + const upb_FieldDef* f, + upb_Arena* a); -/* Well-known field tag numbers for duration messages. */ -#define kUpb_Timestamp_SecondsFieldNumber 1 -#define kUpb_Timestamp_NanosFieldNumber 2 +/* May only be called for fields where upb_FieldDef_HasPresence(f) == true. */ +bool upb_Message_Has(const upb_Message* msg, const upb_FieldDef* f); -const google_protobuf_MessageOptions* upb_MessageDef_Options( - const upb_MessageDef* m); -bool upb_MessageDef_HasOptions(const upb_MessageDef* m); -const char* upb_MessageDef_FullName(const upb_MessageDef* m); -const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m); -const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m); -const char* upb_MessageDef_Name(const upb_MessageDef* m); -upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m); -upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m); -int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m); -int upb_MessageDef_FieldCount(const upb_MessageDef* m); -int upb_MessageDef_OneofCount(const upb_MessageDef* m); -const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, - int i); -const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i); -const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i); -const upb_FieldDef* upb_MessageDef_FindFieldByNumber(const upb_MessageDef* m, - uint32_t i); -const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( - const upb_MessageDef* m, const char* name, size_t len); -const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( - const upb_MessageDef* m, const char* name, size_t len); -const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m); +/* Returns the field that is set in the oneof, or NULL if none are set. */ +const upb_FieldDef* upb_Message_WhichOneof(const upb_Message* msg, + const upb_OneofDef* o); -UPB_INLINE const upb_OneofDef* upb_MessageDef_FindOneofByName( - const upb_MessageDef* m, const char* name) { - return upb_MessageDef_FindOneofByNameWithSize(m, name, strlen(name)); -} +/* Sets the given field to the given value. For a msg/array/map/string, the + * caller must ensure that the target data outlives |msg| (by living either in + * the same arena or a different arena that outlives it). + * + * Returns false if allocation fails. */ +bool upb_Message_Set(upb_Message* msg, const upb_FieldDef* f, + upb_MessageValue val, upb_Arena* a); -UPB_INLINE const upb_FieldDef* upb_MessageDef_FindFieldByName( - const upb_MessageDef* m, const char* name) { - return upb_MessageDef_FindFieldByNameWithSize(m, name, strlen(name)); -} +/* Clears any field presence and sets the value back to its default. */ +void upb_Message_ClearField(upb_Message* msg, const upb_FieldDef* f); -UPB_INLINE bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m) { - return google_protobuf_MessageOptions_map_entry(upb_MessageDef_Options(m)); -} +/* Clear all data and unknown fields. */ +void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m); -/* Nested entities. */ -int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m); -int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m); -int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m); -const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, - int i); -const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i); -const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, - int i); +/* Iterate over present fields. + * + * size_t iter = kUpb_Message_Begin; + * const upb_FieldDef *f; + * upb_MessageValue val; + * while (upb_Message_Next(msg, m, ext_pool, &f, &val, &iter)) { + * process_field(f, val); + * } + * + * If ext_pool is NULL, no extensions will be returned. If the given symtab + * returns extensions that don't match what is in this message, those extensions + * will be skipped. + */ -/* Lookup of either field or oneof by name. Returns whether either was found. - * If the return is true, then the found def will be set, and the non-found - * one set to NULL. */ -bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, - const char* name, size_t len, - const upb_FieldDef** f, - const upb_OneofDef** o); +#define kUpb_Message_Begin -1 +bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, const upb_FieldDef** f, + upb_MessageValue* val, size_t* iter); -UPB_INLINE bool upb_MessageDef_FindByName(const upb_MessageDef* m, - const char* name, - const upb_FieldDef** f, - const upb_OneofDef** o) { - return upb_MessageDef_FindByNameWithSize(m, name, strlen(name), f, o); -} +/* Clears all unknown field data from this message and all submessages. */ +bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, + int maxdepth); -/* Returns a field by either JSON name or regular proto name. */ -const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( - const upb_MessageDef* m, const char* name, size_t len); -UPB_INLINE const upb_FieldDef* upb_MessageDef_FindByJsonName( - const upb_MessageDef* m, const char* name) { - return upb_MessageDef_FindByJsonNameWithSize(m, name, strlen(name)); -} +#ifdef __cplusplus +} /* extern "C" */ +#endif -/* upb_ExtensionRange *********************************************************/ -const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( - const upb_ExtensionRange* r); -bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r); -int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* r); -int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r); +#endif /* UPB_REFLECTION_MESSAGE_H_ */ -/* upb_EnumDef ****************************************************************/ +#ifndef UPB_JSON_ENCODE_H_ +#define UPB_JSON_ENCODE_H_ -const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e); -bool upb_EnumDef_HasOptions(const upb_EnumDef* e); -const char* upb_EnumDef_FullName(const upb_EnumDef* e); -const char* upb_EnumDef_Name(const upb_EnumDef* e); -const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e); -const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e); -int32_t upb_EnumDef_Default(const upb_EnumDef* e); -int upb_EnumDef_ValueCount(const upb_EnumDef* e); -const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i); -const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( - const upb_EnumDef* e, const char* name, size_t len); -const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* e, - int32_t num); -bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num); +// Must be last. -// Convenience wrapper. -UPB_INLINE const upb_EnumValueDef* upb_EnumDef_FindValueByName( - const upb_EnumDef* e, const char* name) { - return upb_EnumDef_FindValueByNameWithSize(e, name, strlen(name)); -} +#ifdef __cplusplus +extern "C" { +#endif -/* upb_EnumValueDef ***********************************************************/ +enum { + /* When set, emits 0/default values. TODO(haberman): proto3 only? */ + upb_JsonEncode_EmitDefaults = 1 << 0, -const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( - const upb_EnumValueDef* e); -bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* e); -const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* e); -const char* upb_EnumValueDef_Name(const upb_EnumValueDef* e); -int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* e); -uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* e); -const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* e); + /* When set, use normal (snake_case) field names instead of JSON (camelCase) + names. */ + upb_JsonEncode_UseProtoNames = 1 << 1, -/* upb_FileDef ****************************************************************/ + /* When set, emits enums as their integer values instead of as their names. */ + upb_JsonEncode_FormatEnumsAsIntegers = 1 << 2 +}; -const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f); -bool upb_FileDef_HasOptions(const upb_FileDef* f); -const char* upb_FileDef_Name(const upb_FileDef* f); -const char* upb_FileDef_Package(const upb_FileDef* f); -upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f); -int upb_FileDef_DependencyCount(const upb_FileDef* f); -int upb_FileDef_PublicDependencyCount(const upb_FileDef* f); -int upb_FileDef_WeakDependencyCount(const upb_FileDef* f); -int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f); -int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f); -int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f); -int upb_FileDef_ServiceCount(const upb_FileDef* f); -const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i); -const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i); -const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i); -const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i); -const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i); -const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i); -const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i); -const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f); -const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f); -const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f); +/* Encodes the given |msg| to JSON format. The message's reflection is given in + * |m|. The symtab in |symtab| is used to find extensions (if NULL, extensions + * will not be printed). + * + * Output is placed in the given buffer, and always NULL-terminated. The output + * size (excluding NULL) is returned. This means that a return value >= |size| + * implies that the output was truncated. (These are the same semantics as + * snprintf()). */ +size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, int options, char* buf, + size_t size, upb_Status* status); -/* upb_MethodDef **************************************************************/ +#ifdef __cplusplus +} /* extern "C" */ +#endif -const google_protobuf_MethodOptions* upb_MethodDef_Options( - const upb_MethodDef* m); -bool upb_MethodDef_HasOptions(const upb_MethodDef* m); -const char* upb_MethodDef_FullName(const upb_MethodDef* m); -int upb_MethodDef_Index(const upb_MethodDef* m); -const char* upb_MethodDef_Name(const upb_MethodDef* m); -const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m); -const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m); -const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m); -bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m); -bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m); -/* upb_ServiceDef *************************************************************/ +#endif /* UPB_JSONENCODE_H_ */ -const google_protobuf_ServiceOptions* upb_ServiceDef_Options( - const upb_ServiceDef* s); -bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s); -const char* upb_ServiceDef_FullName(const upb_ServiceDef* s); -const char* upb_ServiceDef_Name(const upb_ServiceDef* s); -int upb_ServiceDef_Index(const upb_ServiceDef* s); -const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s); -int upb_ServiceDef_MethodCount(const upb_ServiceDef* s); -const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i); -const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, - const char* name); +#ifndef UPB_INTERNAL_ENCODE_H_ +#define UPB_INTERNAL_ENCODE_H_ -/* upb_DefPool ****************************************************************/ +// Must be last. -upb_DefPool* upb_DefPool_New(void); -void upb_DefPool_Free(upb_DefPool* s); -const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, - const char* sym); -const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( - const upb_DefPool* s, const char* sym, size_t len); -const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, - const char* sym); -const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, - const char* sym); -const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, - const char* sym); -const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( - const upb_DefPool* s, const char* sym, size_t len); -const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, - const char* name); -const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, - const char* name); -const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( - const upb_DefPool* s, const char* name, size_t size); -const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, - const char* name); -const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, - const char* name, - size_t len); -const upb_FileDef* upb_DefPool_AddFile( - upb_DefPool* s, const google_protobuf_FileDescriptorProto* file, - upb_Status* status); -size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s); -upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s); -const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable( - const upb_DefPool* s, const upb_MiniTable_Extension* ext); -const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, - const upb_MessageDef* m, - int32_t fieldnum); -const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( - const upb_DefPool* s); -const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, - const upb_MessageDef* m, - size_t* count); +#ifdef __cplusplus +extern "C" { +#endif + +// Encodes a float or double that is round-trippable, but as short as possible. +// These routines are not fully optimal (not guaranteed to be shortest), but are +// short-ish and match the implementation that has been used in protobuf since +// the beginning. +// +// The given buffer size must be at least kUpb_RoundTripBufferSize. +enum { kUpb_RoundTripBufferSize = 32 }; +void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size); +void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size); -/* For generated code only: loads a generated descriptor. */ -typedef struct _upb_DefPool_Init { - struct _upb_DefPool_Init** deps; /* Dependencies of this file. */ - const upb_MiniTable_File* layout; - const char* filename; - upb_StringView descriptor; /* Serialized descriptor. */ -} _upb_DefPool_Init; +#ifdef __cplusplus +} /* extern "C" */ +#endif -// Should only be directly called by tests. This variant lets us suppress -// the use of compiled-in tables, forcing a rebuild of the tables at runtime. -bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, - bool rebuild_minitable); -UPB_INLINE bool _upb_DefPool_LoadDefInit(upb_DefPool* s, - const _upb_DefPool_Init* init) { - return _upb_DefPool_LoadDefInitEx(s, init, false); +#endif /* UPB_INTERNAL_ENCODE_H_ */ + +#ifndef UPB_INTERNAL_VSNPRINTF_COMPAT_H_ +#define UPB_INTERNAL_VSNPRINTF_COMPAT_H_ + +#include + +// Must be last. + +UPB_INLINE int _upb_vsnprintf(char* buf, size_t size, const char* fmt, + va_list ap) { +#if defined(__MINGW64__) || defined(__MINGW32__) || defined(_MSC_VER) + // The msvc runtime has a non-conforming vsnprintf() that requires the + // following compatibility code to become conformant. + int n = -1; + if (size != 0) n = _vsnprintf_s(buf, size, _TRUNCATE, fmt, ap); + if (n == -1) n = _vscprintf(fmt, ap); + return n; +#else + return vsnprintf(buf, size, fmt, ap); +#endif } -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ +#endif // UPB_INTERNAL_VSNPRINTF_COMPAT_H_ -#endif /* UPB_DEF_H_ */ +#ifndef UPB_MINI_TABLE_H_ +#define UPB_MINI_TABLE_H_ -/** upb/reflection.h ************************************************************/ -#ifndef UPB_REFLECTION_H_ -#define UPB_REFLECTION_H_ +// Must be last. #ifdef __cplusplus extern "C" { #endif -typedef union { - bool bool_val; - float float_val; - double double_val; - int32_t int32_val; - int64_t int64_val; - uint32_t uint32_val; - uint64_t uint64_val; - const upb_Map* map_val; - const upb_Message* msg_val; - const upb_Array* array_val; - upb_StringView str_val; -} upb_MessageValue; +const upb_MiniTable_Field* upb_MiniTable_FindFieldByNumber( + const upb_MiniTable* table, uint32_t number); -typedef union { - upb_Map* map; - upb_Message* msg; - upb_Array* array; -} upb_MutableMessageValue; +UPB_INLINE const upb_MiniTable* upb_MiniTable_GetSubMessageTable( + const upb_MiniTable* mini_table, const upb_MiniTable_Field* field) { + return mini_table->subs[field->submsg_index].submsg; +} -upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f); +UPB_INLINE const upb_MiniTable_Enum* upb_MiniTable_GetSubEnumTable( + const upb_MiniTable* mini_table, const upb_MiniTable_Field* field) { + return mini_table->subs[field->submsg_index].subenum; +} -/** upb_Message - * *******************************************************************/ +/** upb_MtDataEncoder *********************************************************/ -/* Creates a new message of the given type in the given arena. */ -upb_Message* upb_Message_New(const upb_MessageDef* m, upb_Arena* a); +// Functions to encode a string in a format that can be loaded by +// upb_MiniTable_Build(). -/* Returns the value associated with this field. */ -upb_MessageValue upb_Message_Get(const upb_Message* msg, const upb_FieldDef* f); +typedef enum { + kUpb_MessageModifier_ValidateUtf8 = 1 << 0, + kUpb_MessageModifier_DefaultIsPacked = 1 << 1, + kUpb_MessageModifier_IsExtendable = 1 << 2, +} kUpb_MessageModifier; -/* Returns a mutable pointer to a map, array, or submessage value. If the given - * arena is non-NULL this will construct a new object if it was not previously - * present. May not be called for primitive fields. */ -upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, - const upb_FieldDef* f, - upb_Arena* a); +typedef enum { + kUpb_FieldModifier_IsRepeated = 1 << 0, + kUpb_FieldModifier_IsPacked = 1 << 1, + kUpb_FieldModifier_IsClosedEnum = 1 << 2, + kUpb_FieldModifier_IsProto3Singular = 1 << 3, + kUpb_FieldModifier_IsRequired = 1 << 4, +} kUpb_FieldModifier; -/* May only be called for fields where upb_FieldDef_HasPresence(f) == true. */ -bool upb_Message_Has(const upb_Message* msg, const upb_FieldDef* f); +typedef struct { + char* end; // Limit of the buffer passed as a parameter. + // Aliased to internal-only members in .cc. + char internal[32]; +} upb_MtDataEncoder; -/* Returns the field that is set in the oneof, or NULL if none are set. */ -const upb_FieldDef* upb_Message_WhichOneof(const upb_Message* msg, - const upb_OneofDef* o); +// If the input buffer has at least this many bytes available, the encoder call +// is guaranteed to succeed (as long as field number order is maintained). +#define kUpb_MtDataEncoder_MinSize 16 -/* Sets the given field to the given value. For a msg/array/map/string, the - * caller must ensure that the target data outlives |msg| (by living either in - * the same arena or a different arena that outlives it). - * - * Returns false if allocation fails. */ -bool upb_Message_Set(upb_Message* msg, const upb_FieldDef* f, - upb_MessageValue val, upb_Arena* a); +// Encodes field/oneof information for a given message. The sequence of calls +// should look like: +// +// upb_MtDataEncoder e; +// char buf[256]; +// char* ptr = buf; +// e.end = ptr + sizeof(buf); +// unit64_t msg_mod = ...; // bitwise & of kUpb_MessageModifiers or zero +// ptr = upb_MtDataEncoder_StartMessage(&e, ptr, msg_mod); +// // Fields *must* be in field number order. +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// +// // If oneofs are present. Oneofs must be encoded after regular fields. +// ptr = upb_MiniTable_StartOneof(&e, ptr) +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// +// ptr = upb_MiniTable_StartOneof(&e, ptr); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// +// Oneofs must be encoded after all regular fields. +char* upb_MtDataEncoder_StartMessage(upb_MtDataEncoder* e, char* ptr, + uint64_t msg_mod); +char* upb_MtDataEncoder_PutField(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod); +char* upb_MtDataEncoder_StartOneof(upb_MtDataEncoder* e, char* ptr); +char* upb_MtDataEncoder_PutOneofField(upb_MtDataEncoder* e, char* ptr, + uint32_t field_num); + +// Encodes the set of values for a given enum. The values must be given in +// order (after casting to uint32_t), and repeats are not allowed. +void upb_MtDataEncoder_StartEnum(upb_MtDataEncoder* e); +char* upb_MtDataEncoder_PutEnumValue(upb_MtDataEncoder* e, char* ptr, + uint32_t val); +char* upb_MtDataEncoder_EndEnum(upb_MtDataEncoder* e, char* ptr); -/* Clears any field presence and sets the value back to its default. */ -void upb_Message_ClearField(upb_Message* msg, const upb_FieldDef* f); +/** upb_MiniTable *************************************************************/ -/* Clear all data and unknown fields. */ -void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m); +typedef enum { + kUpb_MiniTablePlatform_32Bit, + kUpb_MiniTablePlatform_64Bit, + kUpb_MiniTablePlatform_Native = + UPB_SIZE(kUpb_MiniTablePlatform_32Bit, kUpb_MiniTablePlatform_64Bit), +} upb_MiniTablePlatform; + +// Builds a mini table from the data encoded in the buffer [data, len]. If any +// errors occur, returns NULL and sets a status message. In the success case, +// the caller must call upb_MiniTable_SetSub*() for all message or proto2 enum +// fields to link the table to the appropriate sub-tables. +upb_MiniTable* upb_MiniTable_Build(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, upb_Status* status); + +// Links a sub-message field to a MiniTable for that sub-message. If a +// sub-message field is not linked, it will be treated as an unknown field +// during parsing, and setting the field will not be allowed. It is possible +// to link the message field later, at which point it will no longer be treated +// as unknown. However there is no synchronization for this operation, which +// means parallel mutation requires external synchronization. +void upb_MiniTable_SetSubMessage(upb_MiniTable* table, + upb_MiniTable_Field* field, + const upb_MiniTable* sub); + +// Links an enum field to a MiniTable for that enum. All enum fields must +// be linked prior to parsing. +void upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTable_Field* field, + const upb_MiniTable_Enum* sub); + +const char* upb_MiniTable_BuildExtension(const char* data, size_t len, + upb_MiniTable_Extension* ext, + const upb_MiniTable* extendee, + upb_MiniTable_Sub sub, + upb_Status* status); + +// Special-case functions for MessageSet layout and map entries. +upb_MiniTable* upb_MiniTable_BuildMessageSet(upb_MiniTablePlatform platform, + upb_Arena* arena); +upb_MiniTable* upb_MiniTable_BuildMapEntry(upb_FieldType key_type, + upb_FieldType value_type, + bool value_is_proto3_enum, + upb_MiniTablePlatform platform, + upb_Arena* arena); + +upb_MiniTable_Enum* upb_MiniTable_BuildEnum(const char* data, size_t len, + upb_Arena* arena, + upb_Status* status); + +// Like upb_MiniTable_Build(), but the user provides a buffer of layout data so +// it can be reused from call to call, avoiding repeated realloc()/free(). +// +// The caller owns `*buf` both before and after the call, and must free() it +// when it is no longer in use. The function will realloc() `*buf` as +// necessary, updating `*size` accordingly. +upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, void** buf, + size_t* buf_size, upb_Status* status); + +// For testing only. +char upb_ToBase92(int8_t ch); +char upb_FromBase92(uint8_t ch); +bool upb_IsTypePackable(upb_FieldType type); -/* Iterate over present fields. - * - * size_t iter = kUpb_Message_Begin; - * const upb_FieldDef *f; - * upb_MessageValue val; - * while (upb_Message_Next(msg, m, ext_pool, &f, &val, &iter)) { - * process_field(f, val); - * } - * - * If ext_pool is NULL, no extensions will be returned. If the given symtab - * returns extensions that don't match what is in this message, those extensions - * will be skipped. - */ +#ifdef __cplusplus +} /* extern "C" */ +#endif -#define kUpb_Message_Begin -1 -bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, - const upb_DefPool* ext_pool, const upb_FieldDef** f, - upb_MessageValue* val, size_t* iter); -/* Clears all unknown field data from this message and all submessages. */ -bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, - int maxdepth); +#endif /* UPB_MINI_TABLE_H_ */ -/** upb_Array *****************************************************************/ +#ifndef UPB_REFLECTION_DEF_BUILDER_H_ +#define UPB_REFLECTION_DEF_BUILDER_H_ -/* Creates a new array on the given arena that holds elements of this type. */ -upb_Array* upb_Array_New(upb_Arena* a, upb_CType type); -/* Returns the size of the array. */ -size_t upb_Array_Size(const upb_Array* arr); +// Must be last. -/* Returns the given element, which must be within the array's current size. */ -upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i); +// We want to copy the options verbatim into the destination options proto. +// We use serialize+parse as our deep copy. +#define UBP_DEF_SET_OPTIONS(target, desc_type, options_type, proto) \ + if (google_protobuf_##desc_type##_has_options(proto)) { \ + size_t size; \ + char* pb = google_protobuf_##options_type##_serialize( \ + google_protobuf_##desc_type##_options(proto), ctx->tmp_arena, &size); \ + if (!pb) _upb_DefBuilder_OomErr(ctx); \ + target = \ + google_protobuf_##options_type##_parse(pb, size, _upb_DefBuilder_Arena(ctx)); \ + if (!target) _upb_DefBuilder_OomErr(ctx); \ + } else { \ + target = (const google_protobuf_##options_type*)kUpbDefOptDefault; \ + } -/* Sets the given element, which must be within the array's current size. */ -void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val); +#ifdef __cplusplus +extern "C" { +#endif -/* Appends an element to the array. Returns false on allocation failure. */ -bool upb_Array_Append(upb_Array* array, upb_MessageValue val, upb_Arena* arena); +struct upb_DefBuilder { + upb_DefPool* symtab; + upb_FileDef* file; // File we are building. + upb_Arena* arena; // Allocate defs here. + upb_Arena* tmp_arena; // For temporary allocations. + upb_Status* status; // Record errors here. + const upb_MiniTable_File* layout; // NULL if we should build layouts. + int enum_count; // Count of enums built so far. + int msg_count; // Count of messages built so far. + int ext_count; // Count of extensions built so far. + jmp_buf err; // longjmp() on error. +}; -/* Moves elements within the array using memmove(). Like memmove(), the source - * and destination elements may be overlapping. */ -void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx, - size_t count); +extern const char* kUpbDefOptDefault; -/* Inserts one or more empty elements into the array. Existing elements are - * shifted right. The new elements have undefined state and must be set with - * `upb_Array_Set()`. - * REQUIRES: `i <= upb_Array_Size(arr)` */ -bool upb_Array_Insert(upb_Array* array, size_t i, size_t count, - upb_Arena* arena); +// ctx->status has already been set elsewhere so just fail/longjmp() +UPB_NORETURN void _upb_DefBuilder_FailJmp(upb_DefBuilder* ctx); -/* Deletes one or more elements from the array. Existing elements are shifted - * left. - * REQUIRES: `i + count <= upb_Array_Size(arr)` */ -void upb_Array_Delete(upb_Array* array, size_t i, size_t count); +UPB_NORETURN void _upb_DefBuilder_Errf(upb_DefBuilder* ctx, const char* fmt, + ...) UPB_PRINTF(2, 3); +UPB_NORETURN void _upb_DefBuilder_OomErr(upb_DefBuilder* ctx); -/* Changes the size of a vector. New elements are initialized to empty/0. - * Returns false on allocation failure. */ -bool upb_Array_Resize(upb_Array* array, size_t size, upb_Arena* arena); +const char* _upb_DefBuilder_MakeFullName(upb_DefBuilder* ctx, + const char* prefix, + upb_StringView name); -/** upb_Map *******************************************************************/ +// Given a symbol and the base symbol inside which it is defined, +// find the symbol's definition. +const void* _upb_DefBuilder_ResolveAny(upb_DefBuilder* ctx, + const char* from_name_dbg, + const char* base, upb_StringView sym, + upb_deftype_t* type); -/* Creates a new map on the given arena with the given key/value size. */ -upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type); +const void* _upb_DefBuilder_Resolve(upb_DefBuilder* ctx, + const char* from_name_dbg, const char* base, + upb_StringView sym, upb_deftype_t type); -/* Returns the number of entries in the map. */ -size_t upb_Map_Size(const upb_Map* map); +char _upb_DefBuilder_ParseEscape(upb_DefBuilder* ctx, const upb_FieldDef* f, + const char** src, const char* end); -/* Stores a value for the given key into |*val| (or the zero value if the key is - * not present). Returns whether the key was present. The |val| pointer may be - * NULL, in which case the function tests whether the given key is present. */ -bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, - upb_MessageValue* val); +const char* _upb_DefBuilder_FullToShort(const char* fullname); -/* Removes all entries in the map. */ -void upb_Map_Clear(upb_Map* map); +UPB_INLINE void* _upb_DefBuilder_Alloc(upb_DefBuilder* ctx, size_t bytes) { + if (bytes == 0) return NULL; + void* ret = upb_Arena_Malloc(ctx->arena, bytes); + if (!ret) _upb_DefBuilder_OomErr(ctx); + return ret; +} -/* Sets the given key to the given value. Returns true if this was a new key in - * the map, or false if an existing key was replaced. */ -bool upb_Map_Set(upb_Map* map, upb_MessageValue key, upb_MessageValue val, - upb_Arena* arena); +// Adds a symbol |v| to the symtab, which must be a def pointer previously +// packed with pack_def(). The def's pointer to upb_FileDef* must be set before +// adding, so we know which entries to remove if building this file fails. +UPB_INLINE void _upb_DefBuilder_Add(upb_DefBuilder* ctx, const char* name, + upb_value v) { + upb_StringView sym = {.data = name, .size = strlen(name)}; + bool ok = _upb_DefPool_InsertSym(ctx->symtab, sym, v, ctx->status); + if (!ok) _upb_DefBuilder_FailJmp(ctx); +} -/* Deletes this key from the table. Returns true if the key was present. */ -bool upb_Map_Delete(upb_Map* map, upb_MessageValue key); +UPB_INLINE upb_Arena* _upb_DefBuilder_Arena(const upb_DefBuilder* ctx) { + return ctx->arena; +} -/* Map iteration: - * - * size_t iter = kUpb_Map_Begin; - * while (upb_MapIterator_Next(map, &iter)) { - * upb_MessageValue key = upb_MapIterator_Key(map, iter); - * upb_MessageValue val = upb_MapIterator_Value(map, iter); - * - * // If mutating is desired. - * upb_MapIterator_SetValue(map, iter, value2); - * } - */ +UPB_INLINE upb_FileDef* _upb_DefBuilder_File(const upb_DefBuilder* ctx) { + return ctx->file; +} -/* Advances to the next entry. Returns false if no more entries are present. */ -bool upb_MapIterator_Next(const upb_Map* map, size_t* iter); +// This version of CheckIdent() is only called by other, faster versions after +// they detect a parsing error. +void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name, + bool full); -/* Returns true if the iterator still points to a valid entry, or false if the - * iterator is past the last element. It is an error to call this function with - * kUpb_Map_Begin (you must call next() at least once first). */ -bool upb_MapIterator_Done(const upb_Map* map, size_t iter); +// Verify a relative identifier string. The loop is branchless for speed. +UPB_INLINE void _upb_DefBuilder_CheckIdentNotFull(upb_DefBuilder* ctx, + upb_StringView name) { + bool good = name.size > 0; -/* Returns the key and value for this entry of the map. */ -upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter); -upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter); + for (size_t i = 0; i < name.size; i++) { + const char c = name.data[i]; + const char d = c | 0x20; // force lowercase + const bool is_alpha = (('a' <= d) & (d <= 'z')) | (c == '_'); + const bool is_numer = ('0' <= c) & (c <= '9') & (i != 0); -/* Sets the value for this entry. The iterator must not be done, and the - * iterator must not have been initialized const. */ -void upb_MapIterator_SetValue(upb_Map* map, size_t iter, - upb_MessageValue value); + good &= is_alpha | is_numer; + } + + if (!good) _upb_DefBuilder_CheckIdentSlow(ctx, name, false); +} + +// Verify a full identifier string. This is slightly more complicated than +// verifying a relative identifier string because we must track '.' chars. +UPB_INLINE void _upb_DefBuilder_CheckIdentFull(upb_DefBuilder* ctx, + upb_StringView name) { + bool good = name.size > 0; + bool start = true; + + for (size_t i = 0; i < name.size; i++) { + const char c = name.data[i]; + const char d = c | 0x20; // force lowercase + const bool is_alpha = (('a' <= d) & (d <= 'z')) | (c == '_'); + const bool is_numer = ('0' <= c) & (c <= '9') & !start; + const bool is_dot = (c == '.') & !start; + + good &= is_alpha | is_numer | is_dot; + start = is_dot; + } + + if (!good) _upb_DefBuilder_CheckIdentSlow(ctx, name, true); +} #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_REFLECTION_H_ */ +#endif /* UPB_REFLECTION_DEF_BUILDER_H_ */ + +#ifndef UPB_REFLECTION_DESC_STATE_H_ +#define UPB_REFLECTION_DESC_STATE_H_ + -/** upb/json_decode.h ************************************************************/ -#ifndef UPB_JSONDECODE_H_ -#define UPB_JSONDECODE_H_ +// Must be last. +// Manages the storage for mini descriptor strings as they are being encoded. +// TODO(b/234740652): Move some of this state directly into the encoder, maybe. +typedef struct { + upb_MtDataEncoder e; + size_t bufsize; + char* buf; + char* ptr; +} upb_DescState; #ifdef __cplusplus extern "C" { #endif -enum { upb_JsonDecode_IgnoreUnknown = 1 }; +UPB_INLINE void _upb_DescState_Init(upb_DescState* d) { + d->bufsize = kUpb_MtDataEncoder_MinSize * 2; + d->buf = NULL; + d->ptr = NULL; +} -bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, - const upb_MessageDef* m, const upb_DefPool* symtab, - int options, upb_Arena* arena, upb_Status* status); +bool _upb_DescState_Grow(upb_DescState* d, upb_Arena* a); #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_JSONDECODE_H_ */ -/** upb/json_encode.h ************************************************************/ -#ifndef UPB_JSONENCODE_H_ -#define UPB_JSONENCODE_H_ +#endif /* UPB_REFLECTION_DESC_STATE_H_ */ +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +#ifndef UPB_MAP_SORTER_H_ +#define UPB_MAP_SORTER_H_ + + +// Must be last. #ifdef __cplusplus extern "C" { #endif -enum { - /* When set, emits 0/default values. TODO(haberman): proto3 only? */ - upb_JsonEncode_EmitDefaults = 1, +// _upb_mapsorter sorts maps and provides ordered iteration over the entries. +// Since maps can be recursive (map values can be messages which contain other +// maps), _upb_mapsorter can contain a stack of maps. - /* When set, use normal (snake_caes) field names instead of JSON (camelCase) - names. */ - upb_JsonEncode_UseProtoNames = 2 -}; +typedef struct { + upb_tabent const** entries; + int size; + int cap; +} _upb_mapsorter; -/* Encodes the given |msg| to JSON format. The message's reflection is given in - * |m|. The symtab in |symtab| is used to find extensions (if NULL, extensions - * will not be printed). - * - * Output is placed in the given buffer, and always NULL-terminated. The output - * size (excluding NULL) is returned. This means that a return value >= |size| - * implies that the output was truncated. (These are the same semantics as - * snprintf()). */ -size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, - const upb_DefPool* ext_pool, int options, char* buf, - size_t size, upb_Status* status); +typedef struct { + int start; + int pos; + int end; +} _upb_sortedmap; + +UPB_INLINE void _upb_mapsorter_init(_upb_mapsorter* s) { + s->entries = NULL; + s->size = 0; + s->cap = 0; +} + +UPB_INLINE void _upb_mapsorter_destroy(_upb_mapsorter* s) { + if (s->entries) free(s->entries); +} + +UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter* s, const upb_Map* map, + _upb_sortedmap* sorted, upb_MapEntry* ent) { + if (sorted->pos == sorted->end) return false; + const upb_tabent* tabent = s->entries[sorted->pos++]; + upb_StringView key = upb_tabstrview(tabent->key); + _upb_map_fromkey(key, &ent->k, map->key_size); + upb_value val = {tabent->val.val}; + _upb_map_fromvalue(val, &ent->v, map->val_size); + return true; +} + +UPB_INLINE void _upb_mapsorter_popmap(_upb_mapsorter* s, + _upb_sortedmap* sorted) { + s->size = sorted->start; +} + +bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, + const upb_Map* map, _upb_sortedmap* sorted); #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_JSONENCODE_H_ */ -/** upb/port_undef.inc ************************************************************/ +#endif /* UPB_MAP_SORTER_H_ */ + /* See port_def.inc. This should #undef all macros #defined there. */ #undef UPB_SIZE @@ -5587,6 +7277,7 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #undef UPB_ALIGN_DOWN #undef UPB_ALIGN_MALLOC #undef UPB_ALIGN_OF +#undef UPB_MALLOC_ALIGN #undef UPB_LIKELY #undef UPB_UNLIKELY #undef UPB_FORCEINLINE @@ -5610,3 +7301,5 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #undef UPB_UNPOISON_MEMORY_REGION #undef UPB_ASAN #undef UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 +#undef UPB_DEPRECATED +#undef UPB_GNUC_MIN diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec index 9dc373ca3b..692264ca47 100644 --- a/ruby/google-protobuf.gemspec +++ b/ruby/google-protobuf.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = "google-protobuf" - s.version = "3.21.6" + s.version = "3.21.7" git_tag = "v#{s.version.to_s.sub('.rc.', '-rc')}" # Converts X.Y.Z.rc.N to vX.Y.Z-rcN, used for the git tag s.licenses = ["BSD-3-Clause"] s.summary = "Protocol Buffers" diff --git a/ruby/pom.xml b/ruby/pom.xml index 4e07f84022..15fddeb352 100644 --- a/ruby/pom.xml +++ b/ruby/pom.xml @@ -9,7 +9,7 @@ com.google.protobuf.jruby protobuf-jruby - 3.21.6 + 3.21.7 Protocol Buffer JRuby native extension Protocol Buffers are a way of encoding structured data in an efficient yet @@ -76,7 +76,7 @@ com.google.protobuf protobuf-java-util - 3.21.6 + 3.21.7 org.jruby diff --git a/src/BUILD.bazel b/src/BUILD.bazel index a34c0213c2..aae838c732 100644 --- a/src/BUILD.bazel +++ b/src/BUILD.bazel @@ -4,6 +4,7 @@ # Most rules are under google/protobuf. This package exists for convenience. load("@rules_pkg//:mappings.bzl", "pkg_filegroup", "pkg_files", "strip_prefix") +load("@upb//cmake:build_defs.bzl", "staleness_test") load("//conformance:defs.bzl", "conformance_test") pkg_files( @@ -30,7 +31,6 @@ pkg_filegroup( "//src/google/protobuf/stubs:dist_files", "//src/google/protobuf/testing:dist_files", "//src/google/protobuf/util:dist_files", - "//src/google/protobuf/util/internal:dist_files", ], visibility = ["//pkg:__pkg__"], ) @@ -41,3 +41,24 @@ conformance_test( testee = "//conformance:conformance_cpp", text_format_failure_list = "//conformance:text_format_failure_list_cpp.txt", ) + +# Copy the generated file_lists.cmake into a place where the staleness test +# below can use it. +genrule( + name = "copy_cmake_lists", + srcs = ["//pkg:gen_src_file_lists"], + outs = ["cmake_copy/file_lists.cmake"], + cmd = "cp $< $@", + visibility = ["//visibility:private"], +) + +staleness_test( + name = "cmake_lists_staleness_test", + outs = ["file_lists.cmake"], + generated_pattern = "cmake_copy/%s", + # Only run this test if it is explicitly specified on the command line (not + # via //src:all or ...). This file will be automatically updated in a + # GitHub action, so developers should not worry about failures from this + # test. + tags = ["manual"], +) diff --git a/src/file_lists.cmake b/src/file_lists.cmake index e874574e82..eb9a19a048 100644 --- a/src/file_lists.cmake +++ b/src/file_lists.cmake @@ -24,7 +24,6 @@ set(libprotobuf_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/any.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/any_lite.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/arena.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_config.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/arenastring.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/arenaz_sampler.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/importer.cc @@ -54,6 +53,7 @@ set(libprotobuf_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream_impl.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream_impl_lite.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/json/json.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/map.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/map_field.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/message.cc @@ -72,20 +72,6 @@ set(libprotobuf_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/util/delimited_message_util.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_comparator.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_mask_util.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/datapiece.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/default_value_objectwriter.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/error_listener.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/field_mask_utility.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/json_escaping.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/json_objectwriter.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/json_stream_parser.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/object_writer.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/proto_writer.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/protostream_objectsource.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/protostream_objectwriter.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/type_info.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/utility.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/json_util.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/util/message_differencer.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/util/time_util.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/util/type_resolver_util.cc @@ -143,6 +129,7 @@ set(libprotobuf_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream.h ${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream_impl.h ${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream_impl_lite.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/json/json.h ${protobuf_SOURCE_DIR}/src/google/protobuf/map.h ${protobuf_SOURCE_DIR}/src/google/protobuf/map_entry.h ${protobuf_SOURCE_DIR}/src/google/protobuf/map_entry_lite.h @@ -179,24 +166,6 @@ set(libprotobuf_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/util/delimited_message_util.h ${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_comparator.h ${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_mask_util.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/constants.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/datapiece.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/default_value_objectwriter.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/error_listener.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/field_mask_utility.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/json_escaping.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/json_objectwriter.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/json_stream_parser.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/location_tracker.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/object_location_tracker.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/object_source.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/object_writer.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/proto_writer.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/protostream_objectsource.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/protostream_objectwriter.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/structured_objectwriter.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/type_info.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/utility.h ${protobuf_SOURCE_DIR}/src/google/protobuf/util/json_util.h ${protobuf_SOURCE_DIR}/src/google/protobuf/util/message_differencer.h ${protobuf_SOURCE_DIR}/src/google/protobuf/util/time_util.h @@ -210,7 +179,6 @@ set(libprotobuf_hdrs set(libprotobuf_lite_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/any_lite.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/arena.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_config.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/arenastring.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/arenaz_sampler.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/extension_set.cc @@ -350,18 +318,22 @@ set(libprotoc_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/shared_code_generator.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/string_field.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/string_field_lite.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/enum.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/enum_field.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/extension.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/field.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/file.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/generator.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/helpers.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/import_writer.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/line_consumer.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/map_field.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/message.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/message_field.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/names.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_enum.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_extension.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_field.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_file.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_generator.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_message.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/oneof.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/primitive_field.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/text_format_decode_data.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/php/names.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/php/php_generator.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.cc @@ -446,21 +418,24 @@ set(libprotoc_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/shared_code_generator.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/string_field.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/string_field_lite.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/enum.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/enum_field.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/extension.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/field.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/file.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/generator.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/helpers.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/import_writer.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/line_consumer.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/map_field.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/message.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/message_field.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/names.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_enum.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_extension.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_field.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_file.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_generator.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_helpers.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_map_field.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_message.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_message_field.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_nsobject_methods.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_oneof.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_options.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/nsobject_methods.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/oneof.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/options.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/primitive_field.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/text_format_decode_data.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/php/names.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/php/php_generator.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.h @@ -563,7 +538,6 @@ set(test_util_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/annotation_test_util.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_tester.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/test_util.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/type_info_test_helper.cc ) # //pkg:test_util @@ -580,15 +554,13 @@ set(test_util_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/test_util.inc ${protobuf_SOURCE_DIR}/src/google/protobuf/test_util2.h ${protobuf_SOURCE_DIR}/src/google/protobuf/test_util_lite.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/expecting_objectwriter.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/mock_error_listener.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/type_info_test_helper.h ${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_unittest.inc ) # //src/google/protobuf:full_test_srcs set(protobuf_test_files ${protobuf_SOURCE_DIR}/src/google/protobuf/any_test.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_align_test.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_unittest.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/arenastring_unittest.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/arenaz_sampler_test.cc @@ -679,7 +651,9 @@ set(compiler_test_files ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/doc_comment_unittest.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message_serialization_unittest.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/plugin_unittest.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/line_consumer_unittest.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/names_unittest.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/text_format_decode_data_unittest.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/parser_unittest.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/plugin_unittest.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc @@ -712,13 +686,6 @@ set(util_test_files ${protobuf_SOURCE_DIR}/src/google/protobuf/util/delimited_message_util_test.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_comparator_test.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_mask_util_test.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/default_value_objectwriter_test.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/json_objectwriter_test.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/json_stream_parser_test.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/protostream_objectsource_test.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/protostream_objectwriter_test.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/type_info_test_helper.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/json_util_test.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/util/message_differencer_unittest.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/util/time_util_test.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/util/type_resolver_util_test.cc @@ -726,17 +693,6 @@ set(util_test_files # //src/google/protobuf/util:test_proto_srcs set(util_test_protos_files - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/anys.proto - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/books.proto - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/default_value.proto - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/default_value_test.proto - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/field_mask.proto - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/maps.proto - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/oneofs.proto - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/proto3.proto - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/struct.proto - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/timestamp_duration.proto - ${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/wrappers.proto ${protobuf_SOURCE_DIR}/src/google/protobuf/util/json_format.proto ${protobuf_SOURCE_DIR}/src/google/protobuf/util/json_format_proto3.proto ${protobuf_SOURCE_DIR}/src/google/protobuf/util/message_differencer_unittest.proto diff --git a/src/google/protobuf/BUILD.bazel b/src/google/protobuf/BUILD.bazel index 0578e6681c..49632c6295 100644 --- a/src/google/protobuf/BUILD.bazel +++ b/src/google/protobuf/BUILD.bazel @@ -10,6 +10,7 @@ load("//build_defs:cpp_opts.bzl", "COPTS", "LINK_OPTS") package( default_visibility = [ "//:__pkg__", # "public" targets are alias rules in //. + "//json:__subpackages__", ], ) @@ -162,11 +163,66 @@ cc_library( ], ) +cc_library( + name = "arena_align", + srcs = ["arena_align.cc"], + hdrs = ["arena_align.h"], + include_prefix = "google/protobuf", + visibility = [ + "//:__subpackages__", + "//src/google/protobuf:__subpackages__", + ], + deps = [ + "//src/google/protobuf/stubs:lite", + "@com_google_absl//absl/numeric:bits", + ], +) + +cc_library( + name = "arena_cleanup", + hdrs = ["arena_cleanup.h"], + include_prefix = "google/protobuf", + visibility = [ + "//:__subpackages__", + "//src/google/protobuf:__subpackages__", + ], + deps = [ + "@com_google_absl//absl/base:core_headers", + ], +) + +cc_library( + name = "arena_config", + srcs = ["arena_config.cc"], + hdrs = ["arena_config.h"], + include_prefix = "google/protobuf", + visibility = [ + "//:__subpackages__", + "//src/google/protobuf:__subpackages__", + ], + deps = [ + "//src/google/protobuf/stubs:lite", + ], +) + +cc_library( + name = "arena_allocation_policy", + hdrs = ["arena_allocation_policy.h"], + include_prefix = "google/protobuf", + visibility = [ + "//:__subpackages__", + "//src/google/protobuf:__subpackages__", + ], + deps = [ + ":arena_config", + "//src/google/protobuf/stubs:lite", + ], +) + cc_library( name = "arena", srcs = [ "arena.cc", - "arena_config.cc", ], hdrs = [ "arena.h", @@ -180,6 +236,9 @@ cc_library( "//src/google/protobuf:__subpackages__", ], deps = [ + ":arena_allocation_policy", + ":arena_cleanup", + ":arena_config", "//src/google/protobuf/stubs:lite", "@com_google_absl//absl/synchronization", ], @@ -189,7 +248,6 @@ cc_library( name = "protobuf_lite", srcs = [ "any_lite.cc", - "arena_config.cc", "arenastring.cc", "arenaz_sampler.cc", "extension_set.cc", @@ -208,7 +266,6 @@ cc_library( hdrs = [ "any.h", "arena.h", - "arena_config.h", "arena_impl.h", "arenastring.h", "arenaz_sampler.h", @@ -251,6 +308,7 @@ cc_library( # In Bazel 6.0+, these will be `interface_deps`: deps = [ ":arena", + ":arena_config", "//src/google/protobuf/io", "//src/google/protobuf/stubs:lite", "@com_google_absl//absl/container:flat_hash_set", @@ -672,6 +730,22 @@ cc_test( ], ) +cc_test( + name = "arena_align_test", + srcs = ["arena_align_test.cc"], + copts = COPTS + select({ + "//build_defs:config_msvc": [], + "//conditions:default": [ + "-Wno-error=sign-compare", + ], + }), + deps = [ + ":arena_align", + "@com_google_googletest//:gtest", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "arena_unittest", srcs = ["arena_unittest.cc"], diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h index 726cff2f30..01ca5956e8 100644 --- a/src/google/protobuf/any.pb.h +++ b/src/google/protobuf/any.pb.h @@ -15,7 +15,7 @@ #error "your headers." #endif // PROTOBUF_VERSION -#if 3021006 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021007 < PROTOBUF_MIN_PROTOC_VERSION #error "This file was generated by an older version of protoc which is" #error "incompatible with your Protocol Buffer headers. Please" #error "regenerate this file with a newer version of protoc." diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h index 80fecb6e31..20c1f5a78b 100644 --- a/src/google/protobuf/api.pb.h +++ b/src/google/protobuf/api.pb.h @@ -15,7 +15,7 @@ #error "your headers." #endif // PROTOBUF_VERSION -#if 3021006 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021007 < PROTOBUF_MIN_PROTOC_VERSION #error "This file was generated by an older version of protoc which is" #error "incompatible with your Protocol Buffer headers. Please" #error "regenerate this file with a newer version of protoc." diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc index 6ba81f87ab..0e2db2bc00 100644 --- a/src/google/protobuf/arena.cc +++ b/src/google/protobuf/arena.cc @@ -38,6 +38,7 @@ #include #include "absl/synchronization/mutex.h" +#include "google/protobuf/arena_allocation_policy.h" #include "google/protobuf/arena_impl.h" #include "google/protobuf/arenaz_sampler.h" #include "google/protobuf/port.h" @@ -53,6 +54,18 @@ namespace google { namespace protobuf { namespace internal { +namespace { + +// kSentryArenaBlock is used for arenas which can be referenced pre-main. So, +// constexpr is required. +constexpr ArenaBlock kSentryArenaBlock = {}; + +ArenaBlock* SentryArenaBlock() { + // const_cast<> is okay as kSentryArenaBlock will never be mutated. + return const_cast(&kSentryArenaBlock); +} + +} // namespace static SerialArena::Memory AllocateMemory(const AllocationPolicy* policy_ptr, size_t last_size, size_t min_bytes) { @@ -105,28 +118,26 @@ class GetDeallocator { size_t* space_allocated_; }; -constexpr ArenaBlock SerialArena::kSentryBlock; - // It is guaranteed that this is constructed in `b`. IOW, this is not the first // arena and `b` cannot be sentry. SerialArena::SerialArena(ArenaBlock* b, ThreadSafeArena& parent) : ptr_{b->Pointer(kBlockHeaderSize + ThreadSafeArena::kSerialArenaSize)}, limit_{b->Limit()}, head_{b}, - space_allocated_{b->size()}, + space_allocated_{b->size}, parent_{parent} { GOOGLE_DCHECK(!b->IsSentry()); } // It is guaranteed that this is the first SerialArena. Use sentry block. SerialArena::SerialArena(ThreadSafeArena& parent) - : head_{SentryBlock()}, parent_{parent} {} + : head_{SentryArenaBlock()}, parent_{parent} {} // It is guaranteed that this is the first SerialArena but `b` may be user // provided or newly allocated to store AllocationPolicy. SerialArena::SerialArena(FirstSerialArena, ArenaBlock* b, ThreadSafeArena& parent) - : head_{b}, space_allocated_{b->size()}, parent_{parent} { + : head_{b}, space_allocated_{b->size}, parent_{parent} { if (b->IsSentry()) return; set_ptr(b->Pointer(kBlockHeaderSize)); @@ -136,9 +147,9 @@ SerialArena::SerialArena(FirstSerialArena, ArenaBlock* b, void SerialArena::Init(ArenaBlock* b, size_t offset) { set_ptr(b->Pointer(offset)); limit_ = b->Limit(); - set_head(b); - space_used_.relaxed_set(0); - space_allocated_.relaxed_set(b->size()); + head_.store(b, std::memory_order_relaxed); + space_used_.store(0, std::memory_order_relaxed); + space_allocated_.store(b->size, std::memory_order_relaxed); cached_block_length_ = 0; cached_blocks_ = nullptr; } @@ -155,11 +166,11 @@ SerialArena* SerialArena::New(Memory mem, ThreadSafeArena& parent) { template SerialArena::Memory SerialArena::Free(Deallocator deallocator) { ArenaBlock* b = head(); - Memory mem = {b, b->size()}; + Memory mem = {b, b->size}; while (b->next) { b = b->next; // We must first advance before deleting this block deallocator(mem); - mem = {b, b->size()}; + mem = {b, b->size}; } return mem; } @@ -195,8 +206,9 @@ void SerialArena::AllocateNewBlock(size_t n) { // Record how much used in this block. used = static_cast(ptr() - old_head->Pointer(kBlockHeaderSize)); - wasted = old_head->size() - used; - space_used_.relaxed_set(space_used_.relaxed_get() + used); + wasted = old_head->size - used; + space_used_.store(space_used_.load(std::memory_order_relaxed) + used, + std::memory_order_relaxed); } // TODO(sbenza): Evaluate if pushing unused space into the cached blocks is a @@ -204,18 +216,21 @@ void SerialArena::AllocateNewBlock(size_t n) { // but with a CPU regression. The regression might have been an artifact of // the microbenchmark. - auto mem = AllocateMemory(parent_.AllocPolicy(), old_head->size(), n); + auto mem = AllocateMemory(parent_.AllocPolicy(), old_head->size, n); // We don't want to emit an expensive RMW instruction that requires // exclusive access to a cacheline. Hence we write it in terms of a // regular add. - space_allocated_.relaxed_set(space_allocated_.relaxed_get() + mem.size); + space_allocated_.store( + space_allocated_.load(std::memory_order_relaxed) + mem.size, + std::memory_order_relaxed); ThreadSafeArenaStats::RecordAllocateStats(parent_.arena_stats_.MutableStats(), /*used=*/used, /*allocated=*/mem.size, wasted); auto* new_head = new (mem.ptr) ArenaBlock{old_head, mem.size}; - set_head(new_head); set_ptr(new_head->Pointer(kBlockHeaderSize)); limit_ = new_head->Limit(); + // Previous writes must take effect before writing new head. + head_.store(new_head, std::memory_order_release); #ifdef ADDRESS_SANITIZER ASAN_POISON_MEMORY_REGION(ptr(), limit_ - ptr()); @@ -230,15 +245,15 @@ uint64_t SerialArena::SpaceUsed() const { // usage of the *current* block. // TODO(mkruskal) Consider eliminating this race in exchange for a possible // performance hit on ARM (see cl/455186837). - const ArenaBlock* h = head(); + const ArenaBlock* h = head_.load(std::memory_order_acquire); if (h->IsSentry()) return 0; - const uint64_t current_block_size = h->size(); + const uint64_t current_block_size = h->size; uint64_t current_space_used = std::min( static_cast( ptr() - const_cast(h)->Pointer(kBlockHeaderSize)), current_block_size); - return current_space_used + space_used_.relaxed_get(); + return current_space_used + space_used_.load(std::memory_order_relaxed); } void SerialArena::CleanupList() { @@ -299,10 +314,10 @@ void SerialArena::CleanupList() { // struct SerialArenaChunkHeader { // SerialArenaChunk* next_chunk; // uint32_t capacity; -// Atomic size; +// std::atomic size; // } header; -// Atomic ids[]; -// Atomic arenas[]; +// std::atomic ids[]; +// std::atomic arenas[]; // }; // // where the size of "ids" and "arenas" is determined at runtime; hence the use @@ -313,7 +328,7 @@ struct SerialArenaChunkHeader { ThreadSafeArena::SerialArenaChunk* next_chunk; uint32_t capacity; - Atomic size; + std::atomic size; }; class ThreadSafeArena::SerialArenaChunk { @@ -321,14 +336,14 @@ class ThreadSafeArena::SerialArenaChunk { SerialArenaChunk(uint32_t capacity, void* me, SerialArena* serial) { new (&header()) SerialArenaChunkHeader{capacity, 1}; - new (&id(0)) Atomic{me}; + new (&id(0)) std::atomic{me}; for (uint32_t i = 1; i < capacity; ++i) { - new (&id(i)) Atomic{nullptr}; + new (&id(i)) std::atomic{nullptr}; } - new (&arena(0)) Atomic{serial}; + new (&arena(0)) std::atomic{serial}; for (uint32_t i = 1; i < capacity; ++i) { - new (&arena(i)) Atomic{nullptr}; + new (&arena(i)) std::atomic{nullptr}; } } @@ -346,29 +361,29 @@ class ThreadSafeArena::SerialArenaChunk { void set_capacity(uint32_t capacity) { header().capacity = capacity; } // ids: returns up to size(). - absl::Span> ids() const { + absl::Span> ids() const { return Layout(capacity()).Slice(ptr()).first(safe_size()); } - absl::Span> ids() { + absl::Span> ids() { return Layout(capacity()).Slice(ptr()).first(safe_size()); } - Atomic& id(uint32_t i) { + std::atomic& id(uint32_t i) { GOOGLE_DCHECK_LT(i, capacity()); return Layout(capacity()).Pointer(ptr())[i]; } // arenas: returns up to size(). - absl::Span> arenas() const { + absl::Span> arenas() const { return Layout(capacity()).Slice(ptr()).first(safe_size()); } - absl::Span> arenas() { + absl::Span> arenas() { return Layout(capacity()).Slice(ptr()).first(safe_size()); } - const Atomic& arena(uint32_t i) const { + const std::atomic& arena(uint32_t i) const { GOOGLE_DCHECK_LT(i, capacity()); return Layout(capacity()).Pointer(ptr())[i]; } - Atomic& arena(uint32_t i) { + std::atomic& arena(uint32_t i) { GOOGLE_DCHECK_LT(i, capacity()); return Layout(capacity()).Pointer(ptr())[i]; } @@ -382,16 +397,16 @@ class ThreadSafeArena::SerialArenaChunk { // other paths, either race is not possible (GetSerialArenaFallback) or must // be prevented by users (CleanupList, Free). bool insert(void* me, SerialArena* serial) { - uint32_t idx = size().relaxed_fetch_add(1); + uint32_t idx = size().fetch_add(1, std::memory_order_relaxed); // Bail out if this chunk is full. if (idx >= capacity()) { // Write old value back to avoid potential overflow. - size().relaxed_set(capacity()); + size().store(capacity(), std::memory_order_relaxed); return false; } - id(idx).relaxed_set(me); - arena(idx).relaxed_set(serial); + id(idx).store(me, std::memory_order_relaxed); + arena(idx).store(serial, std::memory_order_release); return true; } @@ -402,9 +417,8 @@ class ThreadSafeArena::SerialArenaChunk { constexpr static int kIds = 1; constexpr static int kArenas = 2; - using layout_type = - absl::container_internal::Layout, - Atomic>; + using layout_type = absl::container_internal::Layout< + SerialArenaChunkHeader, std::atomic, std::atomic>; const char* ptr() const { return reinterpret_cast(this); } char* ptr() { return reinterpret_cast(this); } @@ -416,13 +430,13 @@ class ThreadSafeArena::SerialArenaChunk { return *layout_type::Partial().Pointer(ptr()); } - Atomic& size() { return header().size; } - const Atomic& size() const { return header().size; } + std::atomic& size() { return header().size; } + const std::atomic& size() const { return header().size; } // Returns the size capped by the capacity as fetch_add may result in a size // greater than capacity. uint32_t safe_size() const { - return std::min(capacity(), size().relaxed_get()); + return std::min(capacity(), size().load(std::memory_order_relaxed)); } constexpr static layout_type Layout(size_t n) { @@ -487,7 +501,7 @@ ThreadSafeArena::ThreadSafeArena(void* mem, size_t size, ArenaBlock* ThreadSafeArena::FirstBlock(void* buf, size_t size) { GOOGLE_DCHECK_EQ(reinterpret_cast(buf) & 7, 0u); if (buf == nullptr || size <= kBlockHeaderSize) { - return SerialArena::SentryBlock(); + return SentryArenaBlock(); } // Record user-owned block. alloc_policy_.set_is_user_owned_initial_block(true); @@ -553,7 +567,8 @@ uint64_t ThreadSafeArena::GetNextLifeCycleId() { // On platforms that don't support uint64_t atomics we can certainly not // afford to increment by large intervals and expect uniqueness due to // wrapping, hence we only add by 1. - id = lifecycle_id_generator_.id.relaxed_fetch_add(1) * kInc; + id = lifecycle_id_generator_.id.fetch_add(1, std::memory_order_relaxed) * + kInc; } tc.next_lifecycle_id = id + kDelta; return id; @@ -588,7 +603,7 @@ ThreadSafeArena::SerialArenaChunk* ThreadSafeArena::NewSerialArenaChunk( // Tries to reserve an entry by atomic fetch_add. If the head chunk is already // full (size >= capacity), acquires the mutex and adds a new head. void ThreadSafeArena::AddSerialArena(void* id, SerialArena* serial) { - SerialArenaChunk* head = head_.atomic_get(); + SerialArenaChunk* head = head_.load(std::memory_order_acquire); // Fast path without acquiring mutex. if (!head->IsSentry() && head->insert(id, serial)) { return; @@ -598,7 +613,7 @@ void ThreadSafeArena::AddSerialArena(void* id, SerialArena* serial) { absl::MutexLock lock(&mutex_); // Refetch and if someone else installed a new head, try allocating on that! - SerialArenaChunk* new_head = head_.atomic_get(); + SerialArenaChunk* new_head = head_.load(std::memory_order_acquire); if (new_head != head) { if (new_head->insert(id, serial)) return; // Update head to link to the latest one. @@ -610,7 +625,7 @@ void ThreadSafeArena::AddSerialArena(void* id, SerialArena* serial) { // Use "std::memory_order_release" to make sure prior stores are visible after // this one. - head_.atomic_set(new_head); + head_.store(new_head, std::memory_order_release); } void ThreadSafeArena::Init() { @@ -622,7 +637,7 @@ void ThreadSafeArena::Init() { GOOGLE_DCHECK_EQ(tag_and_id_, kMessageOwnedArena); } arena_stats_ = Sample(); - head_.relaxed_set(SentrySerialArenaChunk()); + head_.store(SentrySerialArenaChunk(), std::memory_order_relaxed); GOOGLE_DCHECK_EQ(message_owned, IsMessageOwned()); first_owner_ = &thread_cache(); @@ -659,12 +674,12 @@ SerialArena::Memory ThreadSafeArena::Free(size_t* space_allocated) { auto deallocator = GetDeallocator(alloc_policy_.get(), space_allocated); WalkSerialArenaChunk([deallocator](SerialArenaChunk* chunk) { - absl::Span> span = chunk->arenas(); + absl::Span> span = chunk->arenas(); // Walks arenas backward to handle the first serial arena the last. Freeing // in reverse-order to the order in which objects were created may not be // necessary to Free and we should revisit this. (b/247560530) for (auto it = span.rbegin(); it != span.rend(); ++it) { - SerialArena* serial = it->relaxed_get(); + SerialArena* serial = it->load(std::memory_order_relaxed); GOOGLE_DCHECK_NE(serial, nullptr); // Always frees the first block of "serial" as it cannot be user-provided. SerialArena::Memory mem = serial->Free(deallocator); @@ -702,7 +717,7 @@ uint64_t ThreadSafeArena::Reset() { : kBlockHeaderSize + kAllocPolicySize; first_arena_.Init(new (mem.ptr) ArenaBlock{nullptr, mem.size}, offset); } else { - first_arena_.Init(SerialArena::SentryBlock(), 0); + first_arena_.Init(SentryArenaBlock(), 0); } // Since the first block and potential alloc_policy on the first block is @@ -725,21 +740,21 @@ void* ThreadSafeArena::AllocateAlignedWithCleanup(size_t n, size_t align, void ThreadSafeArena::AddCleanup(void* elem, void (*cleanup)(void*)) { SerialArena* arena; if (PROTOBUF_PREDICT_FALSE(!GetSerialArenaFast(&arena))) { - arena = GetSerialArenaFallback(); + arena = GetSerialArenaFallback(kMaxCleanupNodeSize); } - arena->AddCleanup(elem, cleanup, AllocPolicy(), arena_stats_.MutableStats()); + arena->AddCleanup(elem, cleanup); } PROTOBUF_NOINLINE void* ThreadSafeArena::AllocateAlignedWithCleanupFallback( size_t n, size_t align, void (*destructor)(void*)) { - return GetSerialArenaFallback()->AllocateAlignedWithCleanup(n, align, - destructor); + return GetSerialArenaFallback(n + kMaxCleanupNodeSize) + ->AllocateAlignedWithCleanup(n, align, destructor); } template void ThreadSafeArena::WalkConstSerialArenaChunk(Functor fn) const { - const SerialArenaChunk* chunk = head_.atomic_get(); + const SerialArenaChunk* chunk = head_.load(std::memory_order_acquire); for (; !chunk->IsSentry(); chunk = chunk->next_chunk()) { fn(chunk); @@ -751,7 +766,7 @@ void ThreadSafeArena::WalkSerialArenaChunk(Functor fn) { // By omitting an Acquire barrier we help the sanitizer that any user code // that doesn't properly synchronize Reset() or the destructor will throw a // TSAN warning. - SerialArenaChunk* chunk = head_.relaxed_get(); + SerialArenaChunk* chunk = head_.load(std::memory_order_relaxed); while (!chunk->IsSentry()) { // Cache next chunk in case this chunk is destroyed. @@ -765,7 +780,7 @@ template void ThreadSafeArena::PerConstSerialArenaInChunk(Functor fn) const { WalkConstSerialArenaChunk([&fn](const SerialArenaChunk* chunk) { for (const auto& each : chunk->arenas()) { - const SerialArena* serial = each.relaxed_get(); + const SerialArena* serial = each.load(std::memory_order_acquire); // It is possible that newly added SerialArena is not updated although // size was. This is acceptable for SpaceAllocated and SpaceUsed. if (serial == nullptr) continue; @@ -796,7 +811,7 @@ uint64_t ThreadSafeArena::SpaceUsed() const { template PROTOBUF_NOINLINE void* ThreadSafeArena::AllocateAlignedFallback(size_t n) { - return GetSerialArenaFallback()->AllocateAligned(n); + return GetSerialArenaFallback(n)->AllocateAligned(n); } template void* ThreadSafeArena::AllocateAlignedFallback< @@ -806,12 +821,12 @@ template void* void ThreadSafeArena::CleanupList() { WalkSerialArenaChunk([](SerialArenaChunk* chunk) { - absl::Span> span = chunk->arenas(); + absl::Span> span = chunk->arenas(); // Walks arenas backward to handle the first serial arena the last. // Destroying in reverse-order to the construction is often assumed by users // and required not to break inter-object dependencies. (b/247560530) for (auto it = span.rbegin(); it != span.rend(); ++it) { - SerialArena* serial = it->relaxed_get(); + SerialArena* serial = it->load(std::memory_order_relaxed); GOOGLE_DCHECK_NE(serial, nullptr); serial->CleanupList(); } @@ -821,7 +836,7 @@ void ThreadSafeArena::CleanupList() { } PROTOBUF_NOINLINE -SerialArena* ThreadSafeArena::GetSerialArenaFallback() { +SerialArena* ThreadSafeArena::GetSerialArenaFallback(size_t n) { void* const id = &thread_cache(); if (id == first_owner_) { CacheSerialArena(&first_arena_); @@ -831,10 +846,10 @@ SerialArena* ThreadSafeArena::GetSerialArenaFallback() { // Search matching SerialArena. SerialArena* serial = nullptr; WalkConstSerialArenaChunk([&serial, id](const SerialArenaChunk* chunk) { - absl::Span> ids = chunk->ids(); + absl::Span> ids = chunk->ids(); for (uint32_t i = 0; i < ids.size(); ++i) { - if (ids[i].relaxed_get() == id) { - serial = chunk->arena(i).relaxed_get(); + if (ids[i].load(std::memory_order_relaxed) == id) { + serial = chunk->arena(i).load(std::memory_order_relaxed); GOOGLE_DCHECK_NE(serial, nullptr); break; } @@ -843,9 +858,10 @@ SerialArena* ThreadSafeArena::GetSerialArenaFallback() { if (!serial) { // This thread doesn't have any SerialArena, which also means it doesn't - // have any blocks yet. So we'll allocate its first block now. + // have any blocks yet. So we'll allocate its first block now. It must be + // big enough to host SerialArena and the pending request. serial = SerialArena::New( - AllocateMemory(alloc_policy_.get(), 0, kSerialArenaSize), *this); + AllocateMemory(alloc_policy_.get(), 0, n + kSerialArenaSize), *this); AddSerialArena(id, serial); } diff --git a/src/google/protobuf/util/internal/error_listener.cc b/src/google/protobuf/arena_align.cc similarity index 87% rename from src/google/protobuf/util/internal/error_listener.cc rename to src/google/protobuf/arena_align.cc index a6641fda36..882ae5a826 100644 --- a/src/google/protobuf/util/internal/error_listener.cc +++ b/src/google/protobuf/arena_align.cc @@ -28,15 +28,18 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "google/protobuf/util/internal/error_listener.h" +#include "google/protobuf/arena_align.h" + +#include +#include namespace google { namespace protobuf { -namespace util { -namespace converter { +namespace internal { +// There are still compilers (open source) requiring a definition for constexpr. +constexpr size_t ArenaAlignDefault::align; // NOLINT -} // namespace converter -} // namespace util +} // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/arena_align.h b/src/google/protobuf/arena_align.h new file mode 100644 index 0000000000..779d54fbb9 --- /dev/null +++ b/src/google/protobuf/arena_align.h @@ -0,0 +1,155 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file provides alignment utilities for use in arenas. +// +// `ArenaAlign` constains a single `align` data member and provides +// the below functions which operate on the given alignment. +// +// Ceil(size_t n) - rounds `n` up to the nearest `align` boundary. +// Floor(size_t n) - rounds `n` down to the nearest `align` boundary. +// Ceil(T* P) - rounds `p` up to the nearest `align` boundary. +// IsAligned(size_t n) - returns true if `n` is aligned to `align` +// IsAligned(T* p) - returns true if `p` is aligned to `align` +// CheckAligned(T* p) - returns `p`. Checks alignment of `p` in debug. +// +// Additionally there is an optimized `CeilDefaultAligned(T*)` method which is +// equivalent to `Ceil(ArenaAlignDefault().CheckAlign(p))` but more efficiently +// implemented as a 'check only' for ArenaAlignDefault. +// +// These classes allow for generic arena logic using 'alignment policies'. +// +// For example: +// +// template +// void* NaiveAlloc(size_t n, Align align) { +// align.CheckAligned(n); +// uint8_t* ptr = align.CeilDefaultAligned(ptr_); +// ptr_ += n; +// return ptr; +// } +// +// void CallSites() { +// void *p1 = NaiveAlloc(n, ArenaAlignDefault()); +// void *p2 = NaiveAlloc(n, ArenaAlignAs(32)); +// } +// +#ifndef GOOGLE_PROTOBUF_ARENA_ALIGN_H__ +#define GOOGLE_PROTOBUF_ARENA_ALIGN_H__ + +#include +#include + +#include "google/protobuf/stubs/logging.h" +#include "google/protobuf/stubs/common.h" +#include "absl/numeric/bits.h" + +namespace google { +namespace protobuf { +namespace internal { + +struct ArenaAlignDefault { + static constexpr size_t align = 8; // NOLINT + + static constexpr bool IsAligned(size_t n) { return (n & (align - 1)) == 0; } + + template + static bool IsAligned(T* ptr) { + return (reinterpret_cast(ptr) & (align - 1)) == 0; + } + + static constexpr size_t Ceil(size_t n) { return (n + align - 1) & -align; } + static constexpr size_t Floor(size_t n) { return (n & ~(align - 1)); } + + template + T* Ceil(T* ptr) const { + uintptr_t intptr = reinterpret_cast(ptr); + return reinterpret_cast((intptr + align - 1) & -align); + } + + template + T* CeilDefaultAligned(T* ptr) const { + return ArenaAlignDefault().CheckAligned(ptr); + } + + // Address sanitizer enabled alignment check + template + static T* CheckAligned(T* ptr) { + GOOGLE_DCHECK(IsAligned(ptr)) << static_cast(ptr); + return ptr; + } +}; + +struct ArenaAlign { + static constexpr bool IsDefault() { return false; }; + + size_t align = 8; + + constexpr bool IsAligned(size_t n) const { return (n & (align - 1)) == 0; } + + template + bool IsAligned(T* ptr) const { + return (reinterpret_cast(ptr) & (align - 1)) == 0; + } + + constexpr size_t Ceil(size_t n) const { return (n + align - 1) & -align; } + constexpr size_t Floor(size_t n) const { return (n & ~(align - 1)); } + + template + T* Ceil(T* ptr) const { + uintptr_t intptr = reinterpret_cast(ptr); + return reinterpret_cast((intptr + align - 1) & -align); + } + + template + T* CeilDefaultAligned(T* ptr) const { + return Ceil(ArenaAlignDefault().CheckAligned(ptr)); + } + + // Address sanitizer enabled alignment check + template + T* CheckAligned(T* ptr) const { + GOOGLE_DCHECK(IsAligned(ptr)) << static_cast(ptr); + return ptr; + } +}; + +inline ArenaAlign ArenaAlignAs(size_t align) { + // align must be a non zero power of 2 >= 8 + GOOGLE_DCHECK_NE(align, 0); + GOOGLE_DCHECK(absl::has_single_bit(align)) << "Invalid alignment " << align; + return ArenaAlign{align}; +} + +} // namespace internal +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_ARENA_ALIGN_H__ diff --git a/src/google/protobuf/arena_align_test.cc b/src/google/protobuf/arena_align_test.cc new file mode 100644 index 0000000000..6fd15bd6bd --- /dev/null +++ b/src/google/protobuf/arena_align_test.cc @@ -0,0 +1,215 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/arena_align.h" + +#include +#include + +namespace google { +namespace protobuf { +namespace internal { +namespace { + +using ::testing::Eq; + +TEST(ArenaAlignDefault, Align) { + auto align_default = ArenaAlignDefault(); + EXPECT_THAT(align_default.align, Eq(8)); +} + +TEST(ArenaAlignDefault, Floor) { + auto align_default = ArenaAlignDefault(); + EXPECT_THAT(align_default.Floor(0), Eq(0)); + EXPECT_THAT(align_default.Floor(1), Eq(0)); + EXPECT_THAT(align_default.Floor(7), Eq(0)); + EXPECT_THAT(align_default.Floor(8), Eq(8)); + EXPECT_THAT(align_default.Floor(9), Eq(8)); + EXPECT_THAT(align_default.Floor(15), Eq(8)); + EXPECT_THAT(align_default.Floor(16), Eq(16)); +} + +TEST(ArenaAlignDefault, Ceil) { + auto align_default = ArenaAlignDefault(); + EXPECT_THAT(align_default.Ceil(0), Eq(0)); + EXPECT_THAT(align_default.Ceil(1), Eq(8)); + EXPECT_THAT(align_default.Ceil(7), Eq(8)); + EXPECT_THAT(align_default.Ceil(8), Eq(8)); + EXPECT_THAT(align_default.Ceil(9), Eq(16)); + EXPECT_THAT(align_default.Ceil(15), Eq(16)); + EXPECT_THAT(align_default.Ceil(16), Eq(16)); +} + +TEST(ArenaAlignDefault, CeilPtr) { + char p[17] = {0}; + auto align_default = ArenaAlignDefault(); + EXPECT_THAT(align_default.Ceil(p + 0), Eq(p + 0)); + EXPECT_THAT(align_default.Ceil(p + 1), Eq(p + 8)); + EXPECT_THAT(align_default.Ceil(p + 7), Eq(p + 8)); + EXPECT_THAT(align_default.Ceil(p + 8), Eq(p + 8)); + EXPECT_THAT(align_default.Ceil(p + 9), Eq(p + 16)); + EXPECT_THAT(align_default.Ceil(p + 15), Eq(p + 16)); + EXPECT_THAT(align_default.Ceil(p + 16), Eq(p + 16)); +} + +TEST(ArenaAlignDefault, CheckAligned) { + char p[17] = {0}; + auto align_default = ArenaAlignDefault(); + EXPECT_THAT(align_default.CheckAligned(p + 0), Eq(p + 0)); + EXPECT_THAT(align_default.CheckAligned(p + 8), Eq(p + 8)); + EXPECT_THAT(align_default.CheckAligned(p + 16), Eq(p + 16)); +#ifdef PROTOBUF_HAS_DEATH_TEST + EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 1), ".*"); + EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 7), ".*"); + EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 9), ".*"); + EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 15), ".*"); + EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 17), ".*"); +#endif // PROTOBUF_HAS_DEATH_TEST +} + +TEST(ArenaAlignDefault, CeilDefaultAligned) { + char p[17] = {0}; + auto align_default = ArenaAlignDefault(); + EXPECT_THAT(align_default.CeilDefaultAligned(p + 0), Eq(p + 0)); + EXPECT_THAT(align_default.CeilDefaultAligned(p + 8), Eq(p + 8)); + EXPECT_THAT(align_default.CeilDefaultAligned(p + 16), Eq(p + 16)); +#ifdef PROTOBUF_HAS_DEATH_TEST + EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 1), ".*"); + EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 7), ".*"); + EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 9), ".*"); + EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 15), ".*"); + EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 17), ".*"); +#endif // PROTOBUF_HAS_DEATH_TEST +} + +TEST(ArenaAlignDefault, IsAligned) { + auto align_default = ArenaAlignDefault(); + EXPECT_TRUE(align_default.IsAligned(0)); + EXPECT_FALSE(align_default.IsAligned(1)); + EXPECT_FALSE(align_default.IsAligned(7)); + EXPECT_TRUE(align_default.IsAligned(8)); + EXPECT_FALSE(align_default.IsAligned(9)); + EXPECT_FALSE(align_default.IsAligned(15)); + EXPECT_TRUE(align_default.IsAligned(16)); +} + +TEST(ArenaAlign, Align) { + auto align_64 = ArenaAlignAs(64); + EXPECT_THAT(align_64.align, Eq(64)); +} + +TEST(ArenaAlign, Floor) { + auto align_64 = ArenaAlignAs(64); + EXPECT_THAT(align_64.Floor(0), Eq(0)); + EXPECT_THAT(align_64.Floor(1), Eq(0)); + EXPECT_THAT(align_64.Floor(63), Eq(0)); + EXPECT_THAT(align_64.Floor(64), Eq(64)); + EXPECT_THAT(align_64.Floor(65), Eq(64)); + EXPECT_THAT(align_64.Floor(127), Eq(64)); + EXPECT_THAT(align_64.Floor(128), Eq(128)); +} + +TEST(ArenaAlign, Ceil) { + auto align_64 = ArenaAlignAs(64); + EXPECT_THAT(align_64.Ceil(0), Eq(0)); + EXPECT_THAT(align_64.Ceil(1), Eq(64)); + EXPECT_THAT(align_64.Ceil(63), Eq(64)); + EXPECT_THAT(align_64.Ceil(64), Eq(64)); + EXPECT_THAT(align_64.Ceil(65), Eq(128)); + EXPECT_THAT(align_64.Ceil(127), Eq(128)); + EXPECT_THAT(align_64.Ceil(128), Eq(128)); +} + +TEST(ArenaAlign, CeilPtr) { + alignas(64) char p[129] = {0}; + auto align_64 = ArenaAlignAs(64); + EXPECT_THAT(align_64.Ceil(p + 0), Eq(p)); + EXPECT_THAT(align_64.Ceil(p + 1), Eq(p + 64)); + EXPECT_THAT(align_64.Ceil(p + 63), Eq(p + 64)); + EXPECT_THAT(align_64.Ceil(p + 64), Eq(p + 64)); + EXPECT_THAT(align_64.Ceil(p + 65), Eq(p + 128)); + EXPECT_THAT(align_64.Ceil(p + 127), Eq(p + 128)); + EXPECT_THAT(align_64.Ceil(p + 128), Eq(p + 128)); +} + +TEST(ArenaAlign, CheckAligned) { + alignas(128) char p[129] = {0}; + auto align_64 = ArenaAlignAs(64); + EXPECT_THAT(align_64.CheckAligned(p + 0), Eq(p)); + EXPECT_THAT(align_64.CheckAligned(p + 64), Eq(p + 64)); + EXPECT_THAT(align_64.CheckAligned(p + 128), Eq(p + 128)); +#ifdef PROTOBUF_HAS_DEATH_TEST + EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 1), ".*"); + EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 7), ".*"); + EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 8), ".*"); + EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 56), ".*"); + EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 63), ".*"); + EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 65), ".*"); + EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 72), ".*"); + EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 120), ".*"); + EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 129), ".*"); +#endif // PROTOBUF_HAS_DEATH_TEST +} + +TEST(ArenaAlign, CeilDefaultAligned) { + alignas(128) char p[129] = {0}; + auto align_64 = ArenaAlignAs(64); + EXPECT_THAT(align_64.CeilDefaultAligned(p + 0), Eq(p)); + EXPECT_THAT(align_64.CeilDefaultAligned(p + 8), Eq(p + 64)); + EXPECT_THAT(align_64.CeilDefaultAligned(p + 56), Eq(p + 64)); + EXPECT_THAT(align_64.CeilDefaultAligned(p + 64), Eq(p + 64)); + EXPECT_THAT(align_64.CeilDefaultAligned(p + 72), Eq(p + 128)); + EXPECT_THAT(align_64.CeilDefaultAligned(p + 120), Eq(p + 128)); + EXPECT_THAT(align_64.CeilDefaultAligned(p + 128), Eq(p + 128)); +#ifdef PROTOBUF_HAS_DEATH_TEST + EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 1), ".*"); + EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 7), ".*"); + EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 63), ".*"); + EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 65), ".*"); + EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 127), ".*"); + EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 129), ".*"); +#endif // PROTOBUF_HAS_DEATH_TEST +} + +TEST(ArenaAlign, IsAligned) { + auto align_64 = ArenaAlignAs(64); + EXPECT_TRUE(align_64.IsAligned(0)); + EXPECT_FALSE(align_64.IsAligned(1)); + EXPECT_FALSE(align_64.IsAligned(63)); + EXPECT_TRUE(align_64.IsAligned(64)); + EXPECT_FALSE(align_64.IsAligned(65)); + EXPECT_FALSE(align_64.IsAligned(127)); + EXPECT_TRUE(align_64.IsAligned(128)); +} + +} // namespace +} // namespace internal +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/arena_allocation_policy.h b/src/google/protobuf/arena_allocation_policy.h new file mode 100644 index 0000000000..699f8a2253 --- /dev/null +++ b/src/google/protobuf/arena_allocation_policy.h @@ -0,0 +1,126 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_ARENA_ALLOCATION_POLICY_H__ +#define GOOGLE_PROTOBUF_ARENA_ALLOCATION_POLICY_H__ + +#include +#include + +#include "google/protobuf/arena_config.h" + +namespace google { +namespace protobuf { +namespace internal { + +// `AllocationPolicy` defines `Arena` allocation policies. Applications can +// customize the inital and maximum sizes for arena allocation, as well as set +// custom allocation and deallocation functions. `AllocationPolicy` is for +// protocol buffer internal use only, and typically created from a user facing +// public configuration class such as `ArenaOptions`. +struct AllocationPolicy { + static constexpr size_t kDefaultStartBlockSize = 256; + + size_t start_block_size = kDefaultStartBlockSize; + size_t max_block_size = GetDefaultArenaMaxBlockSize(); + + void* (*block_alloc)(size_t) = nullptr; + void (*block_dealloc)(void*, size_t) = nullptr; + + bool IsDefault() const { + return start_block_size == kDefaultStartBlockSize && + max_block_size == GetDefaultArenaMaxBlockSize() && + block_alloc == nullptr && block_dealloc == nullptr; + } +}; + +// Tagged pointer to an AllocationPolicy. +class TaggedAllocationPolicyPtr { + public: + constexpr TaggedAllocationPolicyPtr() : policy_(0) {} + + explicit TaggedAllocationPolicyPtr(AllocationPolicy* policy) + : policy_(reinterpret_cast(policy)) {} + + void set_policy(AllocationPolicy* policy) { + auto bits = policy_ & kTagsMask; + policy_ = reinterpret_cast(policy) | bits; + } + + AllocationPolicy* get() { + return reinterpret_cast(policy_ & kPtrMask); + } + const AllocationPolicy* get() const { + return reinterpret_cast(policy_ & kPtrMask); + } + + AllocationPolicy& operator*() { return *get(); } + const AllocationPolicy& operator*() const { return *get(); } + + AllocationPolicy* operator->() { return get(); } + const AllocationPolicy* operator->() const { return get(); } + + bool is_user_owned_initial_block() const { + return static_cast(get_mask()); + } + void set_is_user_owned_initial_block(bool v) { + set_mask(v); + } + + uintptr_t get_raw() const { return policy_; } + + private: + enum : uintptr_t { + kUserOwnedInitialBlock = 1, + }; + + static constexpr uintptr_t kTagsMask = 7; + static constexpr uintptr_t kPtrMask = ~kTagsMask; + + template + uintptr_t get_mask() const { + return policy_ & kMask; + } + template + void set_mask(bool v) { + if (v) { + policy_ |= kMask; + } else { + policy_ &= ~kMask; + } + } + uintptr_t policy_; +}; + +} // namespace internal +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_ARENA_ALLOCATION_POLICY_H__ diff --git a/src/google/protobuf/arena_cleanup.h b/src/google/protobuf/arena_cleanup.h new file mode 100644 index 0000000000..ee36d1cb43 --- /dev/null +++ b/src/google/protobuf/arena_cleanup.h @@ -0,0 +1,189 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_ARENA_CLEANUP_H__ +#define GOOGLE_PROTOBUF_ARENA_CLEANUP_H__ + +#include +#include +#include + +#include "google/protobuf/stubs/logging.h" +#include "google/protobuf/stubs/common.h" +#include "absl/base/attributes.h" + + + +namespace google { +namespace protobuf { +namespace internal { +namespace cleanup { + +// Helper function invoking the destructor of `object` +template +void arena_destruct_object(void* object) { + reinterpret_cast(object)->~T(); +} + +// Tag defines the type of cleanup / cleanup object. This tag is stored in the +// lowest 2 bits of the `elem` value identifying the type of node. All node +// types must start with a `uintptr_t` that stores `Tag` in its low two bits. +enum class Tag : uintptr_t { + kDynamic = 0, // DynamicNode + kString = 1, // StringNode (std::string) +}; + +// DynamicNode contains the object (`elem`) that needs to be +// destroyed, and the function to destroy it (`destructor`) +// elem must be aligned at minimum on a 4 byte boundary. +struct DynamicNode { + uintptr_t elem; + void (*destructor)(void*); +}; + +// StringNode contains a `std::string` object (`elem`) that needs to be +// destroyed. The lowest 2 bits of `elem` contain the non-zero kString tag. +struct StringNode { + uintptr_t elem; +}; + + +// EnableSpecializedTags() return true if the alignment of tagged objects +// such as std::string allow us to poke tags in the 2 LSB bits. +inline constexpr bool EnableSpecializedTags() { + // For now we require 2 bits + return alignof(std::string) >= 8; +} + +// Adds a cleanup entry identified by `tag` at memory location `pos`. +inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CreateNode(Tag tag, void* pos, + const void* elem_raw, + void (*destructor)(void*)) { + auto elem = reinterpret_cast(elem_raw); + if (EnableSpecializedTags()) { + GOOGLE_DCHECK_EQ(elem & 3, 0ULL); // Must be aligned + switch (tag) { + case Tag::kString: { + StringNode n = {elem | static_cast(Tag::kString)}; + memcpy(pos, &n, sizeof(n)); + return; + } + default: + break; + } + } + DynamicNode n = {elem, destructor}; + memcpy(pos, &n, sizeof(n)); +} + +// Optimization: performs a prefetch on `elem_address`. +inline ABSL_ATTRIBUTE_ALWAYS_INLINE void PrefetchNode( + const void* elem_address) { + (void)elem_address; +} + +// Destroys the node idenitfied by `tag` stored at memory location `pos`. +inline ABSL_ATTRIBUTE_ALWAYS_INLINE void DestroyNode(Tag tag, const void* pos) { + if (EnableSpecializedTags()) { + switch (tag) { + case Tag::kString: { + StringNode n; + memcpy(&n, pos, sizeof(n)); + auto* s = reinterpret_cast(n.elem & ~0x7ULL); + // Some compilers don't like fully qualified explicit dtor calls, + // so use an alias to avoid having to type `::`. + using string_type = std::string; + s->~string_type(); + return; + } + default: + break; + } + } + DynamicNode n; + memcpy(&n, pos, sizeof(n)); + n.destructor(reinterpret_cast(n.elem)); +} + +// Returns the `tag` identifying the type of object for `destructor` or +// kDynamic if `destructor` does not identify a well know object type. +inline ABSL_ATTRIBUTE_ALWAYS_INLINE Tag Type(void (*destructor)(void*)) { + if (EnableSpecializedTags()) { + if (destructor == &arena_destruct_object) { + return Tag::kString; + } + } + return Tag::kDynamic; +} + +// Returns the `tag` identifying the type of object stored at memory location +// `elem`, which represents the first uintptr_t value in the node. +inline ABSL_ATTRIBUTE_ALWAYS_INLINE Tag Type(void* raw) { + if (!EnableSpecializedTags()) return Tag::kDynamic; + + uintptr_t elem; + memcpy(&elem, raw, sizeof(elem)); + switch (static_cast(elem & 0x7ULL)) { + case Tag::kDynamic: + return Tag::kDynamic; + case Tag::kString: + return Tag::kString; + default: + GOOGLE_LOG(FATAL) << "Corrupted cleanup tag: " << (elem & 0x7ULL); + return Tag::kDynamic; + } +} + +// Returns the required size in bytes off the node type identified by `tag`. +inline ABSL_ATTRIBUTE_ALWAYS_INLINE size_t Size(Tag tag) { + if (!EnableSpecializedTags()) return sizeof(DynamicNode); + + switch (tag) { + case Tag::kDynamic: + return sizeof(DynamicNode); + case Tag::kString: + return sizeof(StringNode); + default: + GOOGLE_LOG(FATAL) << "Corrupted cleanup tag: " << static_cast(tag); + return sizeof(DynamicNode); + } +} + +// Returns the required size in bytes off the node type for `destructor`. +inline ABSL_ATTRIBUTE_ALWAYS_INLINE size_t Size(void (*destructor)(void*)) { + return destructor == nullptr ? 0 : Size(Type(destructor)); +} + +} // namespace cleanup +} // namespace internal +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_ARENA_CLEANUP_H__ diff --git a/src/google/protobuf/arena_impl.h b/src/google/protobuf/arena_impl.h index 43056f539f..9d2de93396 100644 --- a/src/google/protobuf/arena_impl.h +++ b/src/google/protobuf/arena_impl.h @@ -43,11 +43,12 @@ #include "google/protobuf/stubs/logging.h" #include "absl/numeric/bits.h" #include "absl/synchronization/mutex.h" -#include "google/protobuf/port.h" - - +#include "google/protobuf/arena_allocation_policy.h" +#include "google/protobuf/arena_cleanup.h" #include "google/protobuf/arena_config.h" #include "google/protobuf/arenaz_sampler.h" +#include "google/protobuf/port.h" + // Must be included last. #include "google/protobuf/port_def.inc" @@ -87,177 +88,33 @@ inline PROTOBUF_ALWAYS_INLINE void* AlignTo(void* p, size_t a) { } } -// Wraps std::atomic to avoid accidentally accessing the atomic variable via -// a default memory order (std::memory_order_seq_cst). -template -struct Atomic { - constexpr explicit Atomic(T v) : val(v) {} - - T relaxed_get() const { return val.load(std::memory_order_relaxed); } - T relaxed_get() { return val.load(std::memory_order_relaxed); } - void relaxed_set(T v) { val.store(v, std::memory_order_relaxed); } - - T atomic_get() const { return val.load(std::memory_order_acquire); } - T atomic_get() { return val.load(std::memory_order_acquire); } - void atomic_set(T v) { val.store(v, std::memory_order_release); } - - T relaxed_fetch_add(T v) { - return val.fetch_add(v, std::memory_order_relaxed); - } - - private: - std::atomic val; -}; - // Arena blocks are variable length malloc-ed objects. The following structure // describes the common header for all blocks. struct ArenaBlock { // For the sentry block with zero-size where ptr_, limit_, cleanup_nodes all // point to "this". constexpr ArenaBlock() - : next(nullptr), cleanup_nodes(this), relaxed_size(0) {} + : next(nullptr), cleanup_nodes(this), size(0) {} ArenaBlock(ArenaBlock* next, size_t size) - : next(next), cleanup_nodes(nullptr), relaxed_size(size) { + : next(next), cleanup_nodes(nullptr), size(size) { GOOGLE_DCHECK_GT(size, sizeof(ArenaBlock)); } char* Pointer(size_t n) { - GOOGLE_DCHECK_LE(n, size()); + GOOGLE_DCHECK_LE(n, size); return reinterpret_cast(this) + n; } - char* Limit() { return Pointer(size() & static_cast(-8)); } + char* Limit() { return Pointer(size & static_cast(-8)); } - size_t size() const { return relaxed_size.relaxed_get(); } - bool IsSentry() const { return size() == 0; } + bool IsSentry() const { return size == 0; } ArenaBlock* const next; void* cleanup_nodes; - - private: - const Atomic relaxed_size; + const size_t size; // data follows }; -namespace cleanup { - -template -void arena_destruct_object(void* object) { - reinterpret_cast(object)->~T(); -} - -enum class Tag : uintptr_t { - kDynamic = 0, // {void* elem, void (*destructor)(void*)} - kString = 1, // std::string* | kString -}; - -constexpr bool EnableSpecializedTags() { - return alignof(std::string) >= 8 - ; -} - -// All node types must start with a `uintptr_t` that stores `Tag` in its low -// two bits. -struct DynamicNode { - uintptr_t elem; - void (*destructor)(void*); -}; - -struct StringNode { - uintptr_t elem; -}; - - -inline PROTOBUF_ALWAYS_INLINE void CreateNode(Tag tag, void* pos, - const void* elem, - void (*destructor)(void*)) { - if (EnableSpecializedTags()) { - switch (tag) { - case Tag::kString: { - StringNode n = {reinterpret_cast(elem) | - static_cast(Tag::kString)}; - memcpy(pos, &n, sizeof(n)); - return; - } - default: - break; - } - } - DynamicNode n = {reinterpret_cast(elem), destructor}; - memcpy(pos, &n, sizeof(n)); -} - -inline PROTOBUF_ALWAYS_INLINE void PrefetchNode(const void* elem_address) { - (void)elem_address; -} - -inline PROTOBUF_ALWAYS_INLINE void DestroyNode(Tag tag, const void* pos) { - if (EnableSpecializedTags()) { - switch (tag) { - case Tag::kString: { - StringNode n; - memcpy(&n, pos, sizeof(n)); - auto* s = reinterpret_cast(n.elem & ~0x7ULL); - // Some compilers don't like fully qualified explicit dtor calls, - // so use an alias to avoid having to type `::`. - using string_type = std::string; - s->~string_type(); - return; - } - default: - break; - } - } - DynamicNode n; - memcpy(&n, pos, sizeof(n)); - n.destructor(reinterpret_cast(n.elem)); -} - -inline PROTOBUF_ALWAYS_INLINE Tag Type(void (*destructor)(void*)) { - if (EnableSpecializedTags()) { - if (destructor == &arena_destruct_object) { - return Tag::kString; - } - } - return Tag::kDynamic; -} - -inline PROTOBUF_ALWAYS_INLINE Tag Type(void* raw) { - if (!EnableSpecializedTags()) return Tag::kDynamic; - - uintptr_t elem; - memcpy(&elem, raw, sizeof(elem)); - switch (static_cast(elem & 0x7ULL)) { - case Tag::kDynamic: - return Tag::kDynamic; - case Tag::kString: - return Tag::kString; - default: - GOOGLE_LOG(FATAL) << "Corrupted cleanup tag: " << (elem & 0x7ULL); - return Tag::kDynamic; - } -} - -inline PROTOBUF_ALWAYS_INLINE size_t Size(Tag tag) { - if (!EnableSpecializedTags()) return sizeof(DynamicNode); - - switch (tag) { - case Tag::kDynamic: - return sizeof(DynamicNode); - case Tag::kString: - return sizeof(StringNode); - default: - GOOGLE_LOG(FATAL) << "Corrupted cleanup tag: " << static_cast(tag); - return sizeof(DynamicNode); - } -} - -inline PROTOBUF_ALWAYS_INLINE size_t Size(void (*destructor)(void*)) { - return destructor == nullptr ? 0 : Size(Type(destructor)); -} - -} // namespace cleanup - using LifecycleIdAtomic = uint64_t; // MetricsCollector collects stats for a particular arena. @@ -293,79 +150,6 @@ class PROTOBUF_EXPORT ArenaMetricsCollector { const bool record_allocs_; }; -struct AllocationPolicy { - static constexpr size_t kDefaultStartBlockSize = 256; - - size_t start_block_size = kDefaultStartBlockSize; - size_t max_block_size = GetDefaultArenaMaxBlockSize(); - void* (*block_alloc)(size_t) = nullptr; - void (*block_dealloc)(void*, size_t) = nullptr; - - bool IsDefault() const { - return start_block_size == kDefaultStartBlockSize && - max_block_size == GetDefaultArenaMaxBlockSize() && - block_alloc == nullptr && block_dealloc == nullptr; - } -}; - -// Tagged pointer to an AllocationPolicy. -class TaggedAllocationPolicyPtr { - public: - constexpr TaggedAllocationPolicyPtr() : policy_(0) {} - - explicit TaggedAllocationPolicyPtr(AllocationPolicy* policy) - : policy_(reinterpret_cast(policy)) {} - - void set_policy(AllocationPolicy* policy) { - auto bits = policy_ & kTagsMask; - policy_ = reinterpret_cast(policy) | bits; - } - - AllocationPolicy* get() { - return reinterpret_cast(policy_ & kPtrMask); - } - const AllocationPolicy* get() const { - return reinterpret_cast(policy_ & kPtrMask); - } - - AllocationPolicy& operator*() { return *get(); } - const AllocationPolicy& operator*() const { return *get(); } - - AllocationPolicy* operator->() { return get(); } - const AllocationPolicy* operator->() const { return get(); } - - bool is_user_owned_initial_block() const { - return static_cast(get_mask()); - } - void set_is_user_owned_initial_block(bool v) { - set_mask(v); - } - - uintptr_t get_raw() const { return policy_; } - - private: - enum : uintptr_t { - kUserOwnedInitialBlock = 1, - }; - - static constexpr uintptr_t kTagsMask = 7; - static constexpr uintptr_t kPtrMask = ~kTagsMask; - - template - uintptr_t get_mask() const { - return policy_ & kMask; - } - template - void set_mask(bool v) { - if (v) { - policy_ |= kMask; - } else { - policy_ &= ~kMask; - } - } - uintptr_t policy_; -}; - enum class AllocationClient { kDefault, kArray }; class ThreadSafeArena; @@ -394,7 +178,9 @@ class PROTOBUF_EXPORT SerialArena { }; void CleanupList(); - uint64_t SpaceAllocated() const { return space_allocated_.relaxed_get(); } + uint64_t SpaceAllocated() const { + return space_allocated_.load(std::memory_order_relaxed); + } uint64_t SpaceUsed() const; bool HasSpace(size_t n) const { @@ -542,8 +328,7 @@ class PROTOBUF_EXPORT SerialArena { } PROTOBUF_ALWAYS_INLINE - void AddCleanup(void* elem, void (*destructor)(void*), - const AllocationPolicy* policy, ThreadSafeArenaStats* stats) { + void AddCleanup(void* elem, void (*destructor)(void*)) { size_t required = cleanup::Size(destructor); if (PROTOBUF_PREDICT_FALSE(!HasSpace(required))) { return AddCleanupFallback(elem, destructor); @@ -577,13 +362,6 @@ class PROTOBUF_EXPORT SerialArena { private: friend class ThreadSafeArena; - static constexpr ArenaBlock kSentryBlock = {}; - - static ArenaBlock* SentryBlock() { - // const_cast<> is okay as kSentryBlock will never be mutated. - return const_cast(&kSentryBlock); - } - // Creates a new SerialArena inside mem using the remaining memory as for // future allocations. // The `parent` arena must outlive the serial arena, which is guaranteed @@ -599,13 +377,13 @@ class PROTOBUF_EXPORT SerialArena { // Next pointer to allocate from. Always 8-byte aligned. Points inside // head_ (and head_->pos will always be non-canonical). We keep these // here to reduce indirection. - Atomic ptr_{nullptr}; + std::atomic ptr_{nullptr}; // Limiting address up to which memory can be allocated from the head block. char* limit_ = nullptr; - Atomic head_{nullptr}; // Head of linked list of blocks. - Atomic space_used_{0}; // Necessary for metrics. - Atomic space_allocated_{0}; + std::atomic head_{nullptr}; // Head of linked list of blocks. + std::atomic space_used_{0}; // Necessary for metrics. + std::atomic space_allocated_{0}; ThreadSafeArena& parent_; // Repeated*Field and Arena play together to reduce memory consumption by @@ -623,13 +401,14 @@ class PROTOBUF_EXPORT SerialArena { CachedBlock** cached_blocks_ = nullptr; // Helper getters/setters to handle relaxed operations on atomic variables. - ArenaBlock* head() { return head_.relaxed_get(); } - const ArenaBlock* head() const { return head_.relaxed_get(); } - void set_head(ArenaBlock* head) { return head_.relaxed_set(head); } + ArenaBlock* head() { return head_.load(std::memory_order_relaxed); } + const ArenaBlock* head() const { + return head_.load(std::memory_order_relaxed); + } - char* ptr() { return ptr_.relaxed_get(); } - const char* ptr() const { return ptr_.relaxed_get(); } - void set_ptr(char* ptr) { return ptr_.relaxed_set(ptr); } + char* ptr() { return ptr_.load(std::memory_order_relaxed); } + const char* ptr() const { return ptr_.load(std::memory_order_relaxed); } + void set_ptr(char* ptr) { return ptr_.store(ptr, std::memory_order_relaxed); } // Constructor is private as only New() should be used. inline SerialArena(ArenaBlock* b, ThreadSafeArena& parent); @@ -770,7 +549,7 @@ class PROTOBUF_EXPORT ThreadSafeArena { // Adding a new chunk to head_ must be protected by mutex_. absl::Mutex mutex_; // Pointer to a linked list of SerialArenaChunk. - Atomic head_{nullptr}; + std::atomic head_{nullptr}; void* first_owner_; // Must be declared after alloc_policy_; otherwise, it may lose info on @@ -812,8 +591,9 @@ class PROTOBUF_EXPORT ThreadSafeArena { return false; } - // Finds SerialArena or creates one if not found. - SerialArena* GetSerialArenaFallback(); + // Finds SerialArena or creates one if not found. When creating a new one, + // create a big enough block to accommodate n bytes. + SerialArena* GetSerialArenaFallback(size_t n); template void* AllocateAlignedFallback(size_t n); @@ -874,7 +654,7 @@ class PROTOBUF_EXPORT ThreadSafeArena { struct alignas(kCacheAlignment) CacheAlignedLifecycleIdGenerator { constexpr CacheAlignedLifecycleIdGenerator() : id{0} {} - Atomic id; + std::atomic id; }; static CacheAlignedLifecycleIdGenerator lifecycle_id_generator_; #if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL) @@ -898,6 +678,7 @@ class PROTOBUF_EXPORT ThreadSafeArena { (sizeof(SerialArena) + 7) & static_cast(-8); static constexpr size_t kAllocPolicySize = AlignUpTo8(sizeof(AllocationPolicy)); + static constexpr size_t kMaxCleanupNodeSize = 16; static_assert(kBlockHeaderSize % 8 == 0, "kBlockHeaderSize must be a multiple of 8."); static_assert(kSerialArenaSize % 8 == 0, diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index 9595520b86..cc8098783a 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -74,7 +74,6 @@ #include "google/protobuf/stubs/logging.h" #include "google/protobuf/compiler/subprocess.h" #include "google/protobuf/compiler/plugin.pb.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/match.h" #include "absl/strings/str_format.h" #include "absl/strings/str_replace.h" diff --git a/src/google/protobuf/compiler/cpp/enum.cc b/src/google/protobuf/compiler/cpp/enum.cc index 2cd152abe9..9ac4e92486 100644 --- a/src/google/protobuf/compiler/cpp/enum.cc +++ b/src/google/protobuf/compiler/cpp/enum.cc @@ -34,14 +34,18 @@ #include "google/protobuf/compiler/cpp/enum.h" +#include #include #include -#include -#include +#include #include +#include -#include "google/protobuf/io/printer.h" -#include "google/protobuf/stubs/strutil.h" +#include "google/protobuf/descriptor.h" +#include "absl/container/btree_map.h" +#include "absl/container/btree_set.h" +#include "absl/container/flat_hash_map.h" +#include "absl/strings/str_cat.h" #include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/cpp/names.h" @@ -49,8 +53,23 @@ namespace google { namespace protobuf { namespace compiler { namespace cpp { - namespace { +absl::flat_hash_map EnumVars( + const EnumDescriptor* enum_, const Options& options, + const EnumValueDescriptor* min, const EnumValueDescriptor* max) { + auto classname = ClassName(enum_, false); + return { + {"Enum", enum_->name()}, + {"Enum_", ResolveKeyword(enum_->name())}, + {"Msg_Enum", classname}, + {"::Msg_Enum", QualifiedClassName(enum_, options)}, + {"Msg_Enum_", + enum_->containing_type() == nullptr ? "" : absl::StrCat(classname, "_")}, + {"kMin", absl::StrCat(min->number())}, + {"kMax", absl::StrCat(max->number())}, + }; +} + // The ARRAYSIZE constant is the max enum value plus 1. If the max enum value // is kint32max, ARRAYSIZE will overflow. In such cases we should omit the // generation of the ARRAYSIZE constant. @@ -63,22 +82,9 @@ bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) { } return max_value != std::numeric_limits::max(); } - -// Returns the number of unique numeric enum values. This is less than -// descriptor->value_count() when there are aliased values. -int CountUniqueValues(const EnumDescriptor* descriptor) { - std::unordered_set values; - for (int i = 0; i < descriptor->value_count(); ++i) { - values.insert(descriptor->value(i)->number()); - } - return values.size(); -} - -struct MinMaxEnumDescriptors { - const EnumValueDescriptor* min; - const EnumValueDescriptor* max; -}; -MinMaxEnumDescriptors EnumLimits(const EnumDescriptor* descriptor) { +} // namespace +EnumGenerator::ValueLimits EnumGenerator::ValueLimits::FromEnum( + const EnumDescriptor* descriptor) { const EnumValueDescriptor* min_desc = descriptor->value(0); const EnumValueDescriptor* max_desc = descriptor->value(0); @@ -90,266 +96,303 @@ MinMaxEnumDescriptors EnumLimits(const EnumDescriptor* descriptor) { max_desc = descriptor->value(i); } } - return {min_desc, max_desc}; -} -// Assumes that HasDescriptorMethods is true. -bool ShouldCacheDenseEnum(const EnumDescriptor* descriptor, - MinMaxEnumDescriptors limits) { - // The conditions here for what is "sparse" are not rigorously - // chosen. We use unsigned values in case the subtraction of min from max - // exceeds the bounds of int. - const unsigned values_range = static_cast(limits.max->number()) - - static_cast(limits.min->number()); - return (values_range < 16u || - values_range < static_cast(descriptor->value_count()) * 2u); + return {min_desc, max_desc}; } -} // namespace - EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, - const std::map& vars, const Options& options) - : descriptor_(descriptor), - classname_(ClassName(descriptor, false)), + : enum_(descriptor), options_(options), generate_array_size_(ShouldGenerateArraySize(descriptor)), - variables_(vars) { - variables_["classname"] = classname_; - variables_["classtype"] = QualifiedClassName(descriptor_, options); - variables_["short_name"] = descriptor_->name(); - variables_["nested_name"] = descriptor_->name(); - variables_["resolved_name"] = ResolveKeyword(descriptor_->name()); - variables_["prefix"] = - (descriptor_->containing_type() == nullptr) ? "" : classname_ + "_"; + has_reflection_(HasDescriptorMethods(enum_->file(), options_)), + limits_(ValueLimits::FromEnum(enum_)) { + // The conditions here for what is "sparse" are not rigorously + // chosen. + size_t values_range = static_cast(limits_.max->number()) - + static_cast(limits_.min->number()); + size_t total_values = static_cast(enum_->value_count()); + should_cache_ = has_reflection_ && + (values_range < 16u || values_range < total_values * 2u); } -EnumGenerator::~EnumGenerator() {} - -void EnumGenerator::GenerateDefinition(io::Printer* printer) { - Formatter format(printer, variables_); - format("enum ${1$$classname$$}$ : int {\n", descriptor_); - format.Indent(); - - for (int i = 0; i < descriptor_->value_count(); i++) { - auto format_value = format; - format_value.Set("name", EnumValueName(descriptor_->value(i))); - // In C++, an value of -2147483648 gets interpreted as the negative of - // 2147483648, and since 2147483648 can't fit in an integer, this produces a - // compiler warning. This works around that issue. - format_value.Set("number", Int32ToString(descriptor_->value(i)->number())); - format_value.Set("deprecation", - DeprecatedAttribute(options_, descriptor_->value(i))); - - if (i > 0) format_value(",\n"); - format_value("${1$$prefix$$name$$}$ $deprecation$= $number$", - descriptor_->value(i)); - } - - if (descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { - // For new enum semantics: generate min and max sentinel values equal to - // INT32_MIN and INT32_MAX - if (descriptor_->value_count() > 0) format(",\n"); - format( - "$classname$_$prefix$INT_MIN_SENTINEL_DO_NOT_USE_ = " - "std::numeric_limits<$int32$>::min(),\n" - "$classname$_$prefix$INT_MAX_SENTINEL_DO_NOT_USE_ = " - "std::numeric_limits<$int32$>::max()"); - } - - format.Outdent(); - format("\n};\n"); - - MinMaxEnumDescriptors enum_limits = EnumLimits(descriptor_); - format( - "$dllexport_decl $bool $classname$_IsValid(int value);\n" - "constexpr $classname$ ${1$$prefix$$short_name$_MIN$}$ = " - "$prefix$$2$;\n" - "constexpr $classname$ ${1$$prefix$$short_name$_MAX$}$ = " - "$prefix$$3$;\n", - descriptor_, EnumValueName(enum_limits.min), - EnumValueName(enum_limits.max)); +void EnumGenerator::GenerateDefinition(io::Printer* p) { + auto v1 = p->WithVars(EnumVars(enum_, options_, limits_.min, limits_.max)); + + auto v2 = p->WithVars({ + {"Msg_Enum_Enum_MIN", + absl::StrCat(p->LookupVar("Msg_Enum_"), enum_->name(), "_MIN"), enum_}, + {"Msg_Enum_Enum_MAX", + absl::StrCat(p->LookupVar("Msg_Enum_"), enum_->name(), "_MAX"), enum_}, + }); + p->Emit( + { + {"values", + [&] { + for (int i = 0; i < enum_->value_count(); ++i) { + const auto* value = enum_->value(i); + p->Emit( + { + { + "Msg_Enum_VALUE", + absl::StrCat(p->LookupVar("Msg_Enum_"), + EnumValueName(value)), + value, + }, + {"kNumber", Int32ToString(value->number())}, + {"DEPRECATED", value->options().deprecated() + ? "PROTOBUF_DEPRECATED_ENUM" + : ""}, + }, + R"cc( + $Msg_Enum_VALUE$$ DEPRECATED$ = $kNumber$, + )cc"); + } + }}, + // Only emit annotations for the $Msg_Enum$ used in the `enum` + // definition. + {"Msg_Enum_annotated", p->LookupVar("Msg_Enum"), enum_}, + {"open_enum_sentinels", + [&] { + if (enum_->is_closed()) { + return; + } + + // For open enum semantics: generate min and max sentinel values + // equal to INT32_MIN and INT32_MAX + p->Emit({{"Msg_Enum_Msg_Enum_", + absl::StrCat(p->LookupVar("Msg_Enum"), "_", + p->LookupVar("Msg_Enum_"))}}, + R"cc( + $Msg_Enum_Msg_Enum_$INT_MIN_SENTINEL_DO_NOT_USE_ = + std::numeric_limits::min(), + $Msg_Enum_Msg_Enum_$INT_MAX_SENTINEL_DO_NOT_USE_ = + std::numeric_limits::max(), + )cc"); + }}, + }, + R"cc( + enum $Msg_Enum_annotated$ : int { + $values$, + $open_enum_sentinels$, + }; + + $dllexport_decl $bool $Msg_Enum$_IsValid(int value); + constexpr $Msg_Enum$ $Msg_Enum_Enum_MIN$ = static_cast<$Msg_Enum$>($kMin$); + constexpr $Msg_Enum$ $Msg_Enum_Enum_MAX$ = static_cast<$Msg_Enum$>($kMax$); + )cc"); if (generate_array_size_) { - format( - "constexpr int ${1$$prefix$$short_name$_ARRAYSIZE$}$ = " - "$prefix$$short_name$_MAX + 1;\n\n", - descriptor_); + p->Emit( + {{"Msg_Enum_Enum_ARRAYSIZE", + absl::StrCat(p->LookupVar("Msg_Enum_"), enum_->name(), "_ARRAYSIZE"), + enum_}}, + R"cc( + constexpr int $Msg_Enum_Enum_ARRAYSIZE$ = $kMax$ + 1; + )cc"); } - if (HasDescriptorMethods(descriptor_->file(), options_)) { - format( - "$dllexport_decl $const ::$proto_ns$::EnumDescriptor* " - "$classname$_descriptor();\n"); + if (has_reflection_) { + p->Emit(R"cc( + $dllexport_decl $const ::$proto_ns$::EnumDescriptor* + $Msg_Enum$_descriptor(); + )cc"); + } else { + p->Emit(R"cc( + const std::string& $Msg_Enum$_Name($Msg_Enum$ value); + )cc"); } - // The _Name and _Parse functions. The lite implementation is table-based, so - // we make sure to keep the tables hidden in the .cc file. - if (!HasDescriptorMethods(descriptor_->file(), options_)) { - format("const std::string& $classname$_Name($classname$ value);\n"); - } - // The _Name() function accepts the enum type itself but also any integral - // type. - format( - "template\n" - "inline const std::string& $classname$_Name(T enum_t_value) {\n" - " static_assert(::std::is_same::value ||\n" - " ::std::is_integral::value,\n" - " \"Incorrect type passed to function $classname$_Name.\");\n"); - if (HasDescriptorMethods(descriptor_->file(), options_)) { - if (ShouldCacheDenseEnum(descriptor_, enum_limits)) { + // There are three possible implementations of $Enum$_Name() and + // $Msg_Enum$_Parse(), depending on whether we are using a dense enum name + // cache or not, and whether or not we have reflection. Very little code is + // shared between the three, so it is split into three Emit() calls. + + // Can't use WithVars here, since callbacks can only be passed to Emit() + // directly. Because this includes $Enum$, it must be a callback. + auto write_assert = [&] { + p->Emit(R"cc( + static_assert(std::is_same::value || + std::is_integral::value, + "Incorrect type passed to $Enum$_Name()."); + )cc"); + }; + + if (should_cache_ || !has_reflection_) { + p->Emit({{"static_assert", write_assert}}, R"cc( + template + const std::string& $Msg_Enum$_Name(T value) { + $static_assert$; + return $Msg_Enum$_Name(static_cast<$Msg_Enum$>(value)); + } + )cc"); + if (should_cache_) { // Using the NameOfEnum routine can be slow, so we create a small // cache of pointers to the std::string objects that reflection // stores internally. This cache is a simple contiguous array of // pointers, so if the enum values are sparse, it's not worth it. - format( - " return " - "$classname$_Name(static_cast<$classname$>(enum_t_value));\n"); + p->Emit(R"cc( + template <> + inline const std::string& $Msg_Enum$_Name($Msg_Enum$ value) { + return ::$proto_ns$::internal::NameOfDenseEnum<$Msg_Enum$_descriptor, + $kMin$, $kMax$>( + static_cast(value)); + } + )cc"); } else { - format( - " return ::$proto_ns$::internal::NameOfEnum(\n" - " $classname$_descriptor(), enum_t_value);\n"); + p->Emit(R"cc( + const std::string& $Msg_Enum$_Name($Msg_Enum$ value); + )cc"); } } else { - format( - " return $classname$_Name(static_cast<$classname$>(enum_t_value));\n"); + p->Emit({{"static_assert", write_assert}}, R"cc( + template + const std::string& $Msg_Enum$_Name(T value) { + $static_assert$; + return ::$proto_ns$::internal::NameOfEnum($Msg_Enum$_descriptor(), value); + } + )cc"); } - format("}\n"); - - if (HasDescriptorMethods(descriptor_->file(), options_)) { - if (ShouldCacheDenseEnum(descriptor_, enum_limits)) { - format( - "template<>\n" - "inline const std::string& $classname$_Name($classname$ value) {\n" - " return ::$proto_ns$::internal::NameOfDenseEnum\n" - " <$classname$_descriptor, $1$, $2$>(static_cast(value));\n" - "}\n", - enum_limits.min->number(), enum_limits.max->number()); - } - format( - "inline bool $classname$_Parse(\n" - " ::absl::string_view name, $classname$* " - "value) " - "{\n" - " return ::$proto_ns$::internal::ParseNamedEnum<$classname$>(\n" - " $classname$_descriptor(), name, value);\n" - "}\n"); + + if (has_reflection_) { + p->Emit(R"cc( + inline bool $Msg_Enum$_Parse(absl::string_view name, $Msg_Enum$* value) { + return ::$proto_ns$::internal::ParseNamedEnum<$Msg_Enum$>( + $Msg_Enum$_descriptor(), name, value); + } + )cc"); } else { - format( - "bool $classname$_Parse(\n" - " ::absl::string_view name, $classname$* " - "value);\n"); + p->Emit(R"cc( + bool $Msg_Enum$_Parse(absl::string_view name, $Msg_Enum$* value); + )cc"); } } -void EnumGenerator::GenerateGetEnumDescriptorSpecializations( - io::Printer* printer) { - Formatter format(printer, variables_); - format( - "template <> struct is_proto_enum< $classtype$> : ::std::true_type " - "{};\n"); - if (HasDescriptorMethods(descriptor_->file(), options_)) { - format( - "template <>\n" - "inline const EnumDescriptor* GetEnumDescriptor< $classtype$>() {\n" - " return $classtype$_descriptor();\n" - "}\n"); +void EnumGenerator::GenerateGetEnumDescriptorSpecializations(io::Printer* p) { + auto v = p->WithVars(EnumVars(enum_, options_, limits_.min, limits_.max)); + + p->Emit(R"cc( + template <> + struct is_proto_enum<$::Msg_Enum$> : std::true_type {}; + )cc"); + if (!has_reflection_) { + return; } + p->Emit(R"cc( + template <> + inline const EnumDescriptor* GetEnumDescriptor<$::Msg_Enum$>() { + return $::Msg_Enum$_descriptor(); + } + )cc"); } -void EnumGenerator::GenerateSymbolImports(io::Printer* printer) const { - Formatter format(printer, variables_); - format("typedef $classname$ $resolved_name$;\n"); - - for (int j = 0; j < descriptor_->value_count(); j++) { - std::string deprecated_attr = - DeprecatedAttribute(options_, descriptor_->value(j)); - format( - "$1$static constexpr $resolved_name$ ${2$$3$$}$ =\n" - " $classname$_$3$;\n", - deprecated_attr, descriptor_->value(j), - EnumValueName(descriptor_->value(j))); +void EnumGenerator::GenerateSymbolImports(io::Printer* p) const { + auto v = p->WithVars(EnumVars(enum_, options_, limits_.min, limits_.max)); + + p->Emit(R"cc( + using $Enum_$ = $Msg_Enum$; + )cc"); + + for (int j = 0; j < enum_->value_count(); ++j) { + const auto* value = enum_->value(j); + p->Emit( + { + {"VALUE", EnumValueName(enum_->value(j)), value}, + {"DEPRECATED", + value->options().deprecated() ? "PROTOBUF_DEPRECATED_ENUM" : ""}, + }, + R"cc( + $DEPRECATED $static constexpr $Enum_$ $VALUE$ = $Msg_Enum$_$VALUE$; + )cc"); } - format( - "static inline bool $nested_name$_IsValid(int value) {\n" - " return $classname$_IsValid(value);\n" - "}\n" - "static constexpr $resolved_name$ ${1$$nested_name$_MIN$}$ =\n" - " $classname$_$nested_name$_MIN;\n" - "static constexpr $resolved_name$ ${1$$nested_name$_MAX$}$ =\n" - " $classname$_$nested_name$_MAX;\n", - descriptor_); + p->Emit( + { + {"Enum_MIN", absl::StrCat(enum_->name(), "_MIN"), enum_}, + {"Enum_MAX", absl::StrCat(enum_->name(), "_MAX"), enum_}, + }, + R"cc( + static inline bool $Enum$_IsValid(int value) { + return $Msg_Enum$_IsValid(value); + } + static constexpr $Enum_$ $Enum_MIN$ = $Msg_Enum$_$Enum$_MIN; + static constexpr $Enum_$ $Enum_MAX$ = $Msg_Enum$_$Enum$_MAX; + )cc"); + if (generate_array_size_) { - format( - "static constexpr int ${1$$nested_name$_ARRAYSIZE$}$ =\n" - " $classname$_$nested_name$_ARRAYSIZE;\n", - descriptor_); + p->Emit( + {{"Enum_ARRAYSIZE", absl::StrCat(enum_->name(), "_ARRAYSIZE"), enum_}}, + R"cc( + static constexpr int $Enum_ARRAYSIZE$ = $Msg_Enum$_$Enum$_ARRAYSIZE; + )cc"); } - if (HasDescriptorMethods(descriptor_->file(), options_)) { - format( - "static inline const ::$proto_ns$::EnumDescriptor*\n" - "$nested_name$_descriptor() {\n" - " return $classname$_descriptor();\n" - "}\n"); + if (has_reflection_) { + p->Emit(R"cc( + static inline const ::$proto_ns$::EnumDescriptor* $Enum$_descriptor() { + return $Msg_Enum$_descriptor(); + } + )cc"); } - format( - "template\n" - "static inline const std::string& $nested_name$_Name(T enum_t_value) {\n" - " static_assert(::std::is_same::value ||\n" - " ::std::is_integral::value,\n" - " \"Incorrect type passed to function $nested_name$_Name.\");\n" - " return $classname$_Name(enum_t_value);\n" - "}\n"); - format( - "static inline bool " - "$nested_name$_Parse(::absl::string_view name,\n" - " $resolved_name$* value) {\n" - " return $classname$_Parse(name, value);\n" - "}\n"); + p->Emit(R"cc( + template + static inline const std::string& $Enum$_Name(T value) { + return $Msg_Enum$_Name(value); + } + static inline bool $Enum$_Parse(absl::string_view name, $Enum_$* value) { + return $Msg_Enum$_Parse(name, value); + } + )cc"); } -void EnumGenerator::GenerateMethods(int idx, io::Printer* printer) { - Formatter format(printer, variables_); - if (HasDescriptorMethods(descriptor_->file(), options_)) { - format( - "const ::$proto_ns$::EnumDescriptor* $classname$_descriptor() {\n" - " ::$proto_ns$::internal::AssignDescriptors(&$desc_table$);\n" - " return $file_level_enum_descriptors$[$1$];\n" - "}\n", - idx); - } - - format( - "bool $classname$_IsValid(int value) {\n" - " switch (value) {\n"); - - // Multiple values may have the same number. Make sure we only cover - // each number once by first constructing a set containing all valid - // numbers, then printing a case statement for each element. +void EnumGenerator::GenerateMethods(int idx, io::Printer* p) { + auto v = p->WithVars(EnumVars(enum_, options_, limits_.min, limits_.max)); - std::set numbers; - for (int j = 0; j < descriptor_->value_count(); j++) { - const EnumValueDescriptor* value = descriptor_->value(j); - numbers.insert(value->number()); - } - - for (std::set::iterator iter = numbers.begin(); iter != numbers.end(); - ++iter) { - format(" case $1$:\n", Int32ToString(*iter)); + if (has_reflection_) { + p->Emit({{"idx", idx}}, R"cc( + const ::$proto_ns$::EnumDescriptor* $Msg_Enum$_descriptor() { + ::$proto_ns$::internal::AssignDescriptors(&$desc_table$); + return $file_level_enum_descriptors$[$idx$]; + } + )cc"); } - format( - " return true;\n" - " default:\n" - " return false;\n" - " }\n" - "}\n" - "\n"); - - if (!HasDescriptorMethods(descriptor_->file(), options_)) { + p->Emit({{"cases", + [&] { + // Multiple values may have the same number. Make sure we only + // cover each number once by first constructing a set containing + // all valid numbers, then printing a case statement for each + // element. + + std::vector numbers; + numbers.reserve(enum_->value_count()); + for (int i = 0; i < enum_->value_count(); ++i) { + numbers.push_back(enum_->value(i)->number()); + } + // Sort and deduplicate `numbers`. + absl::c_sort(numbers); + numbers.erase(std::unique(numbers.begin(), numbers.end()), + numbers.end()); + + for (int n : numbers) { + p->Emit({{"n", n}}, R"cc( + case $n$: + )cc"); + } + }}}, + R"( + bool $Msg_Enum$_IsValid(int value) { + switch (value) { + $cases$; + return true; + default: + return false; + } + } + )"); + + if (!has_reflection_) { // In lite mode (where descriptors are unavailable), we generate separate // tables for mapping between enum names and numbers. The _entries table // contains the bulk of the data and is sorted by name, while @@ -363,119 +406,168 @@ void EnumGenerator::GenerateMethods(int idx, io::Printer* printer) { // numerical value. In cases where there are multiple names for the same // number, we treat the first name appearing in the .proto file as the // canonical one. - std::map name_to_number; - std::map number_to_canonical_name; - for (int i = 0; i < descriptor_->value_count(); i++) { - const EnumValueDescriptor* value = descriptor_->value(i); + + absl::btree_map name_to_number; + absl::flat_hash_map number_to_canonical_name; + for (int i = 0; i < enum_->value_count(); ++i) { + const auto* value = enum_->value(i); name_to_number.emplace(value->name(), value->number()); + // The same number may appear with multiple names, so we use emplace() to // let the first name win. number_to_canonical_name.emplace(value->number(), value->name()); } - format( - "static ::$proto_ns$::internal::ExplicitlyConstructed " - "$classname$_strings[$1$] = {};\n\n", - CountUniqueValues(descriptor_)); - - // We concatenate all the names for a given enum into one big string - // literal. If instead we store an array of string literals, the linker - // seems to put all enum strings for a given .proto file in the same - // section, which hinders its ability to strip out unused strings. - format("static const char $classname$_names[] ="); - for (const auto& p : name_to_number) { - format("\n \"$1$\"", p.first); - } - format(";\n\n"); - - format( - "static const ::$proto_ns$::internal::EnumEntry $classname$_entries[] " - "= {\n"); - int i = 0; - std::map number_to_index; - int data_index = 0; - for (const auto& p : name_to_number) { - format(" { {$classname$_names + $1$, $2$}, $3$ },\n", data_index, - p.first.size(), p.second); - if (number_to_canonical_name[p.second] == p.first) { - number_to_index.emplace(p.second, i); - } - ++i; - data_index += p.first.size(); - } - - format( - "};\n" - "\n" - "static const int $classname$_entries_by_number[] = {\n"); - for (const auto& p : number_to_index) { - format(" $1$, // $2$ -> $3$\n", p.second, p.first, - number_to_canonical_name[p.first]); + // Build the offset table for the strings table. + struct Offset { + int number; + size_t index, byte_offset, len; + }; + std::vector offsets; + size_t index = 0; + size_t offset = 0; + for (const auto& e : name_to_number) { + offsets.push_back(Offset{e.second, index, offset, e.first.size()}); + ++index; + offset += e.first.size(); } - format( - "};\n" - "\n"); - - format( - "const std::string& $classname$_Name(\n" - " $classname$ value) {\n" - " static const bool dummy =\n" - " ::$proto_ns$::internal::InitializeEnumStrings(\n" - " $classname$_entries,\n" - " $classname$_entries_by_number,\n" - " $1$, $classname$_strings);\n" - " (void) dummy;\n" - " int idx = ::$proto_ns$::internal::LookUpEnumName(\n" - " $classname$_entries,\n" - " $classname$_entries_by_number,\n" - " $1$, value);\n" - " return idx == -1 ? ::$proto_ns$::internal::GetEmptyString() :\n" - " $classname$_strings[idx].get();\n" - "}\n", - CountUniqueValues(descriptor_)); - format( - "bool $classname$_Parse(\n" - " ::absl::string_view name, $classname$* " - "value) " - "{\n" - " int int_value;\n" - " bool success = ::$proto_ns$::internal::LookUpEnumValue(\n" - " $classname$_entries, $1$, name, &int_value);\n" - " if (success) {\n" - " *value = static_cast<$classname$>(int_value);\n" - " }\n" - " return success;\n" - "}\n", - descriptor_->value_count()); + absl::c_sort(offsets, [](const auto& a, const auto& b) { + return a.byte_offset < b.byte_offset; + }); + + std::vector offsets_by_number = offsets; + absl::c_sort(offsets_by_number, [](const auto& a, const auto& b) { + return a.number < b.number; + }); + + offsets_by_number.erase( + std::unique( + offsets_by_number.begin(), offsets_by_number.end(), + [](const auto& a, const auto& b) { return a.number == b.number; }), + offsets_by_number.end()); + + p->Emit( + { + {"num_unique", number_to_canonical_name.size()}, + {"num_declared", enum_->value_count()}, + {"names", + // We concatenate all the names for a given enum into one big + // string literal. If instead we store an array of string + // literals, the linker seems to put all enum strings for a given + // .proto file in the same section, which hinders its ability to + // strip out unused strings. + [&] { + for (const auto& e : name_to_number) { + p->Emit({{"name", e.first}}, R"cc( + "$name$" + )cc"); + } + }}, + {"entries", + [&] { + for (const auto& offset : offsets) { + p->Emit({{"number", offset.number}, + {"offset", offset.byte_offset}, + {"len", offset.len}}, + R"cc( + {{&$Msg_Enum$_names[$offset$], $len$}, $number$}, + )cc"); + } + }}, + {"entries_by_number", + [&] { + for (const auto& offset : offsets_by_number) { + p->Emit({{"number", offset.number}, + {"index", offset.index}, + {"name", number_to_canonical_name[offset.number]}}, + R"cc( + $index$, // $number$ -> $name$ + )cc"); + } + }}, + }, + R"cc( + static ::$proto_ns$::internal::ExplicitlyConstructed + $Msg_Enum$_strings[$num_unique$] = {}; + + static const char $Msg_Enum$_names[] = { + $names$, + }; + + static const ::$proto_ns$::internal::EnumEntry $Msg_Enum$_entries[] = + { + $entries$, + }; + + static const int $Msg_Enum$_entries_by_number[] = { + $entries_by_number$, + }; + + const std::string& $Msg_Enum$_Name($Msg_Enum$ value) { + static const bool kDummy = + ::$proto_ns$::internal::InitializeEnumStrings( + $Msg_Enum$_entries, $Msg_Enum$_entries_by_number, + $num_unique$, $Msg_Enum$_strings); + (void)kDummy; + + int idx = ::$proto_ns$::internal::LookUpEnumName( + $Msg_Enum$_entries, $Msg_Enum$_entries_by_number, $num_unique$, + value); + return idx == -1 ? ::$proto_ns$::internal::GetEmptyString() + : $Msg_Enum$_strings[idx].get(); + } + + bool $Msg_Enum$_Parse(absl::string_view name, $Msg_Enum$* value) { + int int_value; + bool success = ::$proto_ns$::internal::LookUpEnumValue( + $Msg_Enum$_entries, $num_declared$, name, &int_value); + if (success) { + *value = static_cast<$Msg_Enum$>(int_value); + } + return success; + } + )cc"); } - if (descriptor_->containing_type() != nullptr) { - std::string parent = ClassName(descriptor_->containing_type(), false); + if (enum_->containing_type() != nullptr) { // Before C++17, we must define the static constants which were // declared in the header, to give the linker a place to put them. // But MSVC++ pre-2015 and post-2017 (version 15.5+) insists that we not. - format( - "#if (__cplusplus < 201703) && " - "(!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))\n"); - - for (int i = 0; i < descriptor_->value_count(); i++) { - format("constexpr $classname$ $1$::$2$;\n", parent, - EnumValueName(descriptor_->value(i))); - } - format( - "constexpr $classname$ $1$::$nested_name$_MIN;\n" - "constexpr $classname$ $1$::$nested_name$_MAX;\n", - parent); - if (generate_array_size_) { - format("constexpr int $1$::$nested_name$_ARRAYSIZE;\n", parent); - } - - format( - "#endif // (__cplusplus < 201703) && " - "(!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))\n"); + p->Emit( + { + {"Msg_", ClassName(enum_->containing_type(), false)}, + {"constexpr_storage", + [&] { + for (int i = 0; i < enum_->value_count(); i++) { + p->Emit({{"VALUE", EnumValueName(enum_->value(i))}}, + R"cc( + constexpr $Msg_Enum$ $Msg_$::$VALUE$; + )cc"); + } + }}, + {"array_size", + [&] { + if (generate_array_size_) { + p->Emit(R"cc( + constexpr int $Msg_$::$Enum$_ARRAYSIZE; + )cc"); + } + }}, + }, + R"( + #if (__cplusplus < 201703) && \ + (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) + + $constexpr_storage$; + constexpr $Msg_Enum$ $Msg_$::$Enum$_MIN; + constexpr $Msg_Enum$ $Msg_$::$Enum$_MAX; + $array_size$; + + #endif // (__cplusplus < 201703) && + // (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) + )"); } } - } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/enum.h b/src/google/protobuf/compiler/cpp/enum.h index 33ec3103d0..95fd549481 100644 --- a/src/google/protobuf/compiler/cpp/enum.h +++ b/src/google/protobuf/compiler/cpp/enum.h @@ -41,62 +41,60 @@ #include "google/protobuf/descriptor.h" #include "google/protobuf/compiler/cpp/options.h" - -namespace google { -namespace protobuf { -namespace io { -class Printer; // printer.h -} -} // namespace protobuf -} // namespace google +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { namespace compiler { namespace cpp { - class EnumGenerator { public: - // See generator.cc for the meaning of dllexport_decl. - EnumGenerator(const EnumDescriptor* descriptor, - const std::map& vars, - const Options& options); + EnumGenerator(const EnumDescriptor* descriptor, const Options& options); + EnumGenerator(const EnumGenerator&) = delete; EnumGenerator& operator=(const EnumGenerator&) = delete; - ~EnumGenerator(); + + ~EnumGenerator() = default; // Generate header code defining the enum. This code should be placed // within the enum's package namespace, but NOT within any class, even for // nested enums. - void GenerateDefinition(io::Printer* printer); + void GenerateDefinition(io::Printer* p); // Generate specialization of GetEnumDescriptor(). // Precondition: in ::google::protobuf namespace. - void GenerateGetEnumDescriptorSpecializations(io::Printer* printer); + void GenerateGetEnumDescriptorSpecializations(io::Printer* p); // For enums nested within a message, generate code to import all the enum's // symbols (e.g. the enum type name, all its values, etc.) into the class's // namespace. This should be placed inside the class definition in the // header. - void GenerateSymbolImports(io::Printer* printer) const; + void GenerateSymbolImports(io::Printer* p) const; // Source file stuff. // Generate non-inline methods related to the enum, such as IsValidValue(). // Goes in the .cc file. EnumDescriptors are stored in an array, idx is // the index in this array that corresponds with this enum. - void GenerateMethods(int idx, io::Printer* printer); + void GenerateMethods(int idx, io::Printer* p); private: - const EnumDescriptor* descriptor_; - const std::string classname_; - const Options& options_; - // whether to generate the *_ARRAYSIZE constant. - const bool generate_array_size_; + friend class FileGenerator; - std::map variables_; + struct ValueLimits { + const EnumValueDescriptor* min = nullptr; + const EnumValueDescriptor* max = nullptr; - friend class FileGenerator; + static ValueLimits FromEnum(const EnumDescriptor* descriptor); + }; + + const EnumDescriptor* enum_; + Options options_; + + bool generate_array_size_; + bool should_cache_; + bool has_reflection_; + ValueLimits limits_; }; } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/enum_field.cc b/src/google/protobuf/compiler/cpp/enum_field.cc index 2a0397ff59..3b8b033a5c 100644 --- a/src/google/protobuf/compiler/cpp/enum_field.cc +++ b/src/google/protobuf/compiler/cpp/enum_field.cc @@ -36,7 +36,6 @@ #include "google/protobuf/io/printer.h" #include "google/protobuf/wire_format.h" -#include "google/protobuf/stubs/strutil.h" #include "google/protobuf/compiler/cpp/field.h" #include "google/protobuf/compiler/cpp/helpers.h" diff --git a/src/google/protobuf/compiler/cpp/extension.cc b/src/google/protobuf/compiler/cpp/extension.cc index 4166b08d71..9b6ddc8938 100644 --- a/src/google/protobuf/compiler/cpp/extension.cc +++ b/src/google/protobuf/compiler/cpp/extension.cc @@ -37,7 +37,6 @@ #include #include "google/protobuf/io/printer.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_replace.h" #include "google/protobuf/compiler/cpp/helpers.h" diff --git a/src/google/protobuf/compiler/cpp/field.cc b/src/google/protobuf/compiler/cpp/field.cc index bc93afa21a..3199dce889 100644 --- a/src/google/protobuf/compiler/cpp/field.cc +++ b/src/google/protobuf/compiler/cpp/field.cc @@ -48,7 +48,6 @@ #include "google/protobuf/stubs/common.h" #include "google/protobuf/io/printer.h" #include "google/protobuf/wire_format.h" -#include "google/protobuf/stubs/strutil.h" #include "google/protobuf/compiler/cpp/enum_field.h" #include "google/protobuf/compiler/cpp/map_field.h" #include "google/protobuf/compiler/cpp/message_field.h" @@ -233,37 +232,72 @@ void AddAccessorAnnotations(const FieldDescriptor* descriptor, "OnAddMutable", variables); } +absl::flat_hash_map FieldVars( + const FieldDescriptor* desc, const Options& opts) { + bool split = ShouldSplit(desc, opts); + absl::flat_hash_map vars = { + {"ns", Namespace(desc, opts)}, + {"name", FieldName(desc)}, + {"index", absl::StrCat(desc->index())}, + {"number", absl::StrCat(desc->number())}, + {"classname", ClassName(FieldScope(desc), false)}, + {"declared_type", DeclaredTypeMethodName(desc->type())}, + {"field", FieldMemberName(desc, split)}, + {"tag_size", + absl::StrCat(WireFormat::TagSize(desc->number(), desc->type()))}, + {"deprecated_attr", DeprecatedAttribute(opts, desc)}, + {"set_hasbit", ""}, + {"clear_hasbit", ""}, + {"maybe_prepare_split_message", + split ? "PrepareSplitMessageForWrite();" : ""}, + + // These variables are placeholders to pick out the beginning and ends of + // identifiers for annotations (when doing so with existing variables + // would be ambiguous or impossible). They should never be set to anything + // but the empty string. + {"{", ""}, + {"}", ""}, + }; + + // TODO(b/245791219): Refactor AddAccessorAnnotations to avoid this + // workaround. + std::map workaround = { + {"field", vars["field"]}, + {"tracker", "Impl_::_tracker_"}, + }; + AddAccessorAnnotations(desc, opts, &workaround); + for (auto& pair : workaround) { + vars.emplace(pair); + } + + return vars; +} + void SetCommonFieldVariables(const FieldDescriptor* descriptor, std::map* variables, const Options& options) { SetCommonMessageDataVariables(descriptor->containing_type(), variables); - (*variables)["ns"] = Namespace(descriptor, options); - (*variables)["name"] = FieldName(descriptor); - (*variables)["index"] = absl::StrCat(descriptor->index()); - (*variables)["number"] = absl::StrCat(descriptor->number()); - (*variables)["classname"] = ClassName(FieldScope(descriptor), false); - (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type()); - bool split = ShouldSplit(descriptor, options); - (*variables)["field"] = FieldMemberName(descriptor, split); - - (*variables)["tag_size"] = absl::StrCat( - WireFormat::TagSize(descriptor->number(), descriptor->type())); - (*variables)["deprecated_attr"] = DeprecatedAttribute(options, descriptor); - - (*variables)["set_hasbit"] = ""; - (*variables)["clear_hasbit"] = ""; - (*variables)["maybe_prepare_split_message"] = - split ? " PrepareSplitMessageForWrite();\n" : ""; - - AddAccessorAnnotations(descriptor, options, variables); - - // These variables are placeholders to pick out the beginning and ends of - // identifiers for annotations (when doing so with existing variables would - // be ambiguous or impossible). They should never be set to anything but the - // empty string. - (*variables)["{"] = ""; - (*variables)["}"] = ""; + for (auto& pair : FieldVars(descriptor, options)) { + variables->emplace(pair); + } +} + +absl::flat_hash_map OneofFieldVars( + const FieldDescriptor* descriptor) { + if (descriptor->containing_oneof() == nullptr) { + return {}; + } + + return {{"oneof_name", descriptor->containing_oneof()->name()}}; +} + +void SetCommonOneofFieldVariables( + const FieldDescriptor* descriptor, + std::map* variables) { + for (auto& pair : OneofFieldVars(descriptor)) { + variables->emplace(pair); + } } void FieldGenerator::SetHasBitIndex(int32_t has_bit_index) { @@ -330,13 +364,6 @@ void FieldGenerator::GenerateCopyConstructorCode(io::Printer* printer) const { } } -void SetCommonOneofFieldVariables( - const FieldDescriptor* descriptor, - std::map* variables) { - const std::string prefix = descriptor->containing_oneof()->name() + "_."; - (*variables)["oneof_name"] = descriptor->containing_oneof()->name(); -} - FieldGenerator::~FieldGenerator() {} FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, diff --git a/src/google/protobuf/compiler/cpp/field.h b/src/google/protobuf/compiler/cpp/field.h index b23a2a680f..db0d64d30e 100644 --- a/src/google/protobuf/compiler/cpp/field.h +++ b/src/google/protobuf/compiler/cpp/field.h @@ -57,6 +57,12 @@ namespace protobuf { namespace compiler { namespace cpp { +absl::flat_hash_map FieldVars( + const FieldDescriptor* desc, const Options& opts); + +absl::flat_hash_map OneofFieldVars( + const FieldDescriptor* descriptor); + // Helper function: set variables in the map that are the same for all // field code generators. // ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size', diff --git a/src/google/protobuf/compiler/cpp/file.cc b/src/google/protobuf/compiler/cpp/file.cc index dc07ed455a..fdb84ac400 100644 --- a/src/google/protobuf/compiler/cpp/file.cc +++ b/src/google/protobuf/compiler/cpp/file.cc @@ -66,6 +66,8 @@ #include "google/protobuf/descriptor.pb.h" #include "google/protobuf/io/printer.h" +#include "google/protobuf/stubs/strutil.h" // for StringReplace. + // Must be last. #include "google/protobuf/port_def.inc" @@ -122,8 +124,8 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) } for (int i = 0; i < file->enum_type_count(); ++i) { - enum_generators_.push_back(absl::make_unique( - file->enum_type(i), variables_, options)); + enum_generators_.push_back( + absl::make_unique(file->enum_type(i), options)); } for (int i = 0; i < file->service_count(); ++i) { @@ -522,7 +524,7 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx, io::Printer* p) { // Generate the split instance first because it's needed in the constexpr // constructor. - if (ShouldSplit(generator->descriptor_, options_)) { + if (ShouldSplit(generator->descriptor(), options_)) { // Use a union to disable the destructor of the _instance member. // We can constant initialize, but the object will still have a non-trivial // destructor that we need to elide. @@ -533,13 +535,14 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx, io::Printer* p) { // there just to improve performance and binary size in these builds. p->Emit( { - {"type", DefaultInstanceType(generator->descriptor_, options_, + {"type", DefaultInstanceType(generator->descriptor(), options_, /*split=*/true)}, - {"name", DefaultInstanceName(generator->descriptor_, options_, + {"name", DefaultInstanceName(generator->descriptor(), options_, /*split=*/true)}, {"default", [&] { generator->GenerateInitDefaultSplitInstance(p); }}, - {"class", absl::StrCat(generator->classname_, "::Impl_::Split")}, + {"class", absl::StrCat(ClassName(generator->descriptor()), + "::Impl_::Split")}, }, R"cc( struct $type$ { @@ -558,10 +561,10 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx, io::Printer* p) { p->Emit( { - {"type", DefaultInstanceType(generator->descriptor_, options_)}, - {"name", DefaultInstanceName(generator->descriptor_, options_)}, + {"type", DefaultInstanceType(generator->descriptor(), options_)}, + {"name", DefaultInstanceName(generator->descriptor(), options_)}, {"default", [&] { generator->GenerateInitDefaultSplitInstance(p); }}, - {"class", generator->classname_}, + {"class", ClassName(generator->descriptor())}, }, R"cc( struct $type$ { @@ -576,8 +579,8 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx, io::Printer* p) { PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 $type$ $name$; )cc"); - for (int i = 0; i < generator->descriptor_->field_count(); ++i) { - const FieldDescriptor* field = generator->descriptor_->field(i); + for (int i = 0; i < generator->descriptor()->field_count(); ++i) { + const FieldDescriptor* field = generator->descriptor()->field(i); if (!IsStringInlined(field, options_)) { continue; } @@ -585,9 +588,9 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx, io::Printer* p) { // Force the initialization of the inlined string in the default instance. p->Emit( { - {"class", ClassName(generator->descriptor_)}, + {"class", ClassName(generator->descriptor())}, {"field", FieldName(field)}, - {"default", DefaultInstanceName(generator->descriptor_, options_)}, + {"default", DefaultInstanceName(generator->descriptor(), options_)}, {"member", FieldMemberName(field, ShouldSplit(field, options_))}, }, R"cc( @@ -600,8 +603,8 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx, io::Printer* p) { if (options_.lite_implicit_weak_fields) { p->Emit( { - {"ptr", DefaultInstancePtr(generator->descriptor_, options_)}, - {"name", DefaultInstanceName(generator->descriptor_, options_)}, + {"ptr", DefaultInstancePtr(generator->descriptor(), options_)}, + {"name", DefaultInstanceName(generator->descriptor(), options_)}, }, R"cc( PROTOBUF_CONSTINIT const void* $ptr$ = &$name$; @@ -709,7 +712,7 @@ void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* p) { } CrossFileReferences refs; - ForEachField(message_generators_[idx]->descriptor_, + ForEachField(message_generators_[idx]->descriptor(), [this, &refs](const FieldDescriptor* field) { GetCrossFileReferencesForField(field, &refs); }); @@ -915,8 +918,8 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* p) { for (auto& gen : message_generators_) { p->Emit( { - {"ns", Namespace(gen->descriptor_, options_)}, - {"class", ClassName(gen->descriptor_)}, + {"ns", Namespace(gen->descriptor(), options_)}, + {"class", ClassName(gen->descriptor())}, }, R"cc( &$ns$::_$class$_default_instance_._instance, @@ -1213,9 +1216,9 @@ void FileGenerator::GenerateForwardDeclarations(io::Printer* p) { decls[Namespace(e, options_)].AddEnum(e); } for (const auto& mg : message_generators_) { - const Descriptor* d = mg->descriptor_; + const Descriptor* d = mg->descriptor(); if (d != nullptr && public_set.count(d->file()) == 0u && - ShouldSplit(mg->descriptor_, options_)) + ShouldSplit(mg->descriptor(), options_)) decls[Namespace(d, options_)].AddSplit(d); } diff --git a/src/google/protobuf/compiler/cpp/generator.cc b/src/google/protobuf/compiler/cpp/generator.cc index 8403312cb2..56a201293e 100644 --- a/src/google/protobuf/compiler/cpp/generator.cc +++ b/src/google/protobuf/compiler/cpp/generator.cc @@ -156,6 +156,7 @@ bool CppGenerator::Generate(const FileDescriptor* file, } } else if (key == "proto_h") { file_options.proto_h = true; + } else if (key == "proto_static_reflection_h") { } else if (key == "annotate_accessor") { file_options.annotate_accessor = true; } else if (key == "inject_field_listener_events") { @@ -209,6 +210,17 @@ bool CppGenerator::Generate(const FileDescriptor* file, std::string basename = StripProto(file->name()); + auto generate_reserved_static_reflection_header = [&basename, + &generator_context]() { + auto output = absl::WrapUnique(generator_context->Open( + absl::StrCat(basename, ".proto.static_reflection.h"))); + io::Printer(output.get()).Emit(R"cc( + // Reserved for future use. + )cc"); + }; + // Suppress maybe unused warning. + (void)generate_reserved_static_reflection_header; + if (MaybeBootstrap(file_options, generator_context, file_options.bootstrap, &basename)) { return true; diff --git a/src/google/protobuf/compiler/cpp/helpers.cc b/src/google/protobuf/compiler/cpp/helpers.cc index c89a48dcc2..e17ccc596d 100644 --- a/src/google/protobuf/compiler/cpp/helpers.cc +++ b/src/google/protobuf/compiler/cpp/helpers.cc @@ -235,46 +235,66 @@ bool IsLazilyVerifiedLazy(const FieldDescriptor* field, return false; } +absl::flat_hash_map MessageVars( + const Descriptor* desc) { + absl::string_view prefix = IsMapEntryMessage(desc) ? "" : "_impl_."; + return { + {"any_metadata", absl::StrCat(prefix, "_any_metadata_")}, + {"cached_size", absl::StrCat(prefix, "_cached_size_")}, + {"extensions", absl::StrCat(prefix, "_extensions_")}, + {"has_bits", absl::StrCat(prefix, "_has_bits_")}, + {"inlined_string_donated_array", + absl::StrCat(prefix, "_inlined_string_donated_")}, + {"oneof_case", absl::StrCat(prefix, "_oneof_case_")}, + {"tracker", "Impl_::_tracker_"}, + {"weak_field_map", absl::StrCat(prefix, "_weak_field_map_")}, + {"split", absl::StrCat(prefix, "_split_")}, + {"cached_split_ptr", "cached_split_ptr"}, + }; +} + void SetCommonMessageDataVariables( const Descriptor* descriptor, std::map* variables) { - std::string prefix = IsMapEntryMessage(descriptor) ? "" : "_impl_."; - (*variables)["any_metadata"] = prefix + "_any_metadata_"; - (*variables)["cached_size"] = prefix + "_cached_size_"; - (*variables)["extensions"] = prefix + "_extensions_"; - (*variables)["has_bits"] = prefix + "_has_bits_"; - (*variables)["inlined_string_donated_array"] = - prefix + "_inlined_string_donated_"; - (*variables)["oneof_case"] = prefix + "_oneof_case_"; - (*variables)["tracker"] = "Impl_::_tracker_"; - (*variables)["weak_field_map"] = prefix + "_weak_field_map_"; - (*variables)["split"] = prefix + "_split_"; - (*variables)["cached_split_ptr"] = "cached_split_ptr"; + for (auto& pair : MessageVars(descriptor)) { + variables->emplace(pair); + } } -void SetUnknownFieldsVariable(const Descriptor* descriptor, - const Options& options, - std::map* variables) { - std::string proto_ns = ProtobufNamespace(options); +absl::flat_hash_map UnknownFieldsVars( + const Descriptor* desc, const Options& opts) { + std::string proto_ns = ProtobufNamespace(opts); + std::string unknown_fields_type; - if (UseUnknownFieldSet(descriptor->file(), options)) { - unknown_fields_type = "::" + proto_ns + "::UnknownFieldSet"; - (*variables)["unknown_fields"] = - "_internal_metadata_.unknown_fields<" + unknown_fields_type + ">(" + - unknown_fields_type + "::default_instance)"; + std::string default_instance; + if (UseUnknownFieldSet(desc->file(), opts)) { + unknown_fields_type = absl::StrCat("::", proto_ns, "::UnknownFieldSet"); + default_instance = absl::StrCat(unknown_fields_type, "::default_instance"); } else { unknown_fields_type = - PrimitiveTypeName(options, FieldDescriptor::CPPTYPE_STRING); - (*variables)["unknown_fields"] = "_internal_metadata_.unknown_fields<" + - unknown_fields_type + ">(::" + proto_ns + - "::internal::GetEmptyString)"; - } - (*variables)["unknown_fields_type"] = unknown_fields_type; - (*variables)["have_unknown_fields"] = - "_internal_metadata_.have_unknown_fields()"; - (*variables)["mutable_unknown_fields"] = - "_internal_metadata_.mutable_unknown_fields<" + unknown_fields_type + - ">()"; + PrimitiveTypeName(opts, FieldDescriptor::CPPTYPE_STRING); + default_instance = + absl::StrCat("::", proto_ns, "::internal::GetEmptyString"); + } + + return { + {"unknown_fields", + absl::Substitute("_internal_metadata_.unknown_fields<$0>($1)", + unknown_fields_type, default_instance)}, + {"unknown_fields_type", unknown_fields_type}, + {"have_unknown_fields", "_internal_metadata_.have_unknown_fields()"}, + {"mutable_unknown_fields", + absl::Substitute("_internal_metadata_.mutable_unknown_fields<$0>()", + unknown_fields_type)}, + }; +} + +void SetUnknownFieldsVariable(const Descriptor* descriptor, + const Options& options, + std::map* variables) { + for (auto& pair : UnknownFieldsVars(descriptor, options)) { + variables->emplace(pair); + } } std::string UnderscoresToCamelCase(const std::string& input, diff --git a/src/google/protobuf/compiler/cpp/helpers.h b/src/google/protobuf/compiler/cpp/helpers.h index 251214f2fa..15df165a79 100644 --- a/src/google/protobuf/compiler/cpp/helpers.h +++ b/src/google/protobuf/compiler/cpp/helpers.h @@ -46,6 +46,7 @@ #include "absl/container/flat_hash_map.h" #include "absl/strings/match.h" #include "absl/strings/str_split.h" +#include "absl/strings/string_view.h" #include "google/protobuf/compiler/cpp/names.h" #include "google/protobuf/compiler/cpp/options.h" #include "google/protobuf/descriptor.pb.h" @@ -88,11 +89,17 @@ inline std::string DeprecatedAttribute(const Options& /* options */, extern const char kThickSeparator[]; extern const char kThinSeparator[]; +absl::flat_hash_map MessageVars( + const Descriptor* desc); + // Variables to access message data from the message scope. void SetCommonMessageDataVariables( const Descriptor* descriptor, std::map* variables); +absl::flat_hash_map UnknownFieldsVars( + const Descriptor* desc, const Options& opts); + void SetUnknownFieldsVariable(const Descriptor* descriptor, const Options& options, std::map* variables); @@ -874,16 +881,26 @@ class PROTOC_EXPORT Formatter { } }; -template -void PrintFieldComment(const Formatter& format, const T* field) { +template +std::string FieldComment(const T* field) { // Print the field's (or oneof's) proto-syntax definition as a comment. // We don't want to print group bodies so we cut off after the first // line. DebugStringOptions options; options.elide_group_body = true; options.elide_oneof_body = true; - std::string def = field->DebugStringWithOptions(options); - format("// $1$\n", def.substr(0, def.find_first_of('\n'))); + + for (absl::string_view chunk : + absl::StrSplit(field->DebugStringWithOptions(options), '\n')) { + return std::string(chunk); + } + + return ""; +} + +template +void PrintFieldComment(const Formatter& format, const T* field) { + format("// $1$\n", FieldComment(field)); } class PROTOC_EXPORT NamespaceOpener { diff --git a/src/google/protobuf/compiler/cpp/map_field.cc b/src/google/protobuf/compiler/cpp/map_field.cc index ab8501d72b..c73be5fc0c 100644 --- a/src/google/protobuf/compiler/cpp/map_field.cc +++ b/src/google/protobuf/compiler/cpp/map_field.cc @@ -32,10 +32,10 @@ #include "google/protobuf/io/printer.h" #include "google/protobuf/wire_format.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/ascii.h" #include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/stubs/strutil.h" namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/cpp/message.cc b/src/google/protobuf/compiler/cpp/message.cc index f450f22502..9d5d621ba6 100644 --- a/src/google/protobuf/compiler/cpp/message.cc +++ b/src/google/protobuf/compiler/cpp/message.cc @@ -35,6 +35,7 @@ #include "google/protobuf/compiler/cpp/message.h" #include +#include #include #include #include @@ -46,13 +47,10 @@ #include #include "google/protobuf/stubs/common.h" -#include "google/protobuf/io/coded_stream.h" -#include "google/protobuf/io/printer.h" #include "google/protobuf/descriptor.h" #include "google/protobuf/generated_message_util.h" #include "google/protobuf/map_entry_lite.h" #include "google/protobuf/wire_format.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/container/flat_hash_map.h" #include "absl/strings/ascii.h" #include "absl/strings/str_cat.h" @@ -67,7 +65,7 @@ #include "google/protobuf/compiler/cpp/padding_optimizer.h" #include "google/protobuf/compiler/cpp/parse_function_generator.h" #include "google/protobuf/descriptor.pb.h" -#include "google/protobuf/generated_message_tctable_gen.h" +#include "google/protobuf/io/printer.h" // Must be included last. @@ -111,9 +109,10 @@ std::string ConditionalToCheckBitmasks( return result + (return_success ? " == 0" : " != 0"); } -void PrintPresenceCheck(const Formatter& format, const FieldDescriptor* field, - const std::vector& has_bit_indices, - io::Printer* printer, int* cached_has_word_index) { +void PrintPresenceCheck(const FieldDescriptor* field, + const std::vector& has_bit_indices, io::Printer* p, + int* cached_has_word_index) { + Formatter format(p); if (!field->options().weak()) { int has_bit_index = has_bit_indices[field->index()]; if (*cached_has_word_index != (has_bit_index / 32)) { @@ -192,10 +191,6 @@ bool CanBeManipulatedAsRawBytes(const FieldDescriptor* field, return ret; } -bool StrContains(const std::string& haystack, const std::string& needle) { - return haystack.find(needle) != std::string::npos; -} - // Finds runs of fields for which `predicate` is true. // RunMap maps from fields that start each run to the number of fields in that // run. This is optimized for the common case that there are very few runs in @@ -224,13 +219,14 @@ RunMap FindRuns(const std::vector& fields, // considered non-default (will be sent over the wire), for message types // without true field presence. Should only be called if // !HasHasbit(field). -bool EmitFieldNonDefaultCondition(io::Printer* printer, - const std::string& prefix, +bool EmitFieldNonDefaultCondition(io::Printer* p, const std::string& prefix, const FieldDescriptor* field) { GOOGLE_CHECK(!HasHasbit(field)); - Formatter format(printer); - format.Set("prefix", prefix); - format.Set("name", FieldName(field)); + Formatter format(p); + auto v = p->WithVars({{ + {"prefix", prefix}, + {"name", FieldName(field)}, + }}); // Merge and serialize semantics: primitive fields are merged/serialized only // if non-zero (numeric) or non-empty (string). if (!field->is_repeated() && !field->containing_oneof()) { @@ -419,8 +415,8 @@ class ColdChunkSkipper { // prefix to _has_bits_ to allow MergeFrom to use "from._has_bits_". // Otherwise, it should be "". void OnStartChunk(int chunk, int cached_has_word_index, - const std::string& from, io::Printer* printer); - bool OnEndChunk(int chunk, io::Printer* printer); + const std::string& from, io::Printer* p); + bool OnEndChunk(int chunk, io::Printer* p); private: bool IsColdChunk(int chunk); @@ -448,9 +444,8 @@ bool ColdChunkSkipper::IsColdChunk(int chunk) { void ColdChunkSkipper::OnStartChunk(int chunk, int cached_has_word_index, - const std::string& from, - io::Printer* printer) { - Formatter format(printer, variables_); + const std::string& from, io::Printer* p) { + Formatter format(p); if (!access_info_map_) { return; } else if (chunk < limit_chunk_) { @@ -474,7 +469,8 @@ void ColdChunkSkipper::OnStartChunk(int chunk, int cached_has_word_index, } // Emit has_bit check for each has_bit_dword index. - format("if (PROTOBUF_PREDICT_FALSE(false"); + format("if (PROTOBUF_PREDICT_FALSE("); + int first_word = HasbitWord(chunk, 0); while (chunk < limit_chunk_) { uint32_t mask = 0; int this_word = HasbitWord(chunk, 0); @@ -488,8 +484,10 @@ void ColdChunkSkipper::OnStartChunk(int chunk, int cached_has_word_index, } } - format(" ||\n "); - format.Set("mask", absl::Hex(mask, absl::kZeroPad8)); + if (this_word != first_word) { + format(" ||\n "); + } + auto v = p->WithVars({{"mask", absl::Hex(mask, absl::kZeroPad8)}}); if (this_word == cached_has_word_index) { format("(cached_has_bits & 0x$mask$u) != 0"); } else { @@ -500,8 +498,8 @@ void ColdChunkSkipper::OnStartChunk(int chunk, int cached_has_word_index, format.Indent(); } -bool ColdChunkSkipper::OnEndChunk(int chunk, io::Printer* printer) { - Formatter format(printer, variables_); +bool ColdChunkSkipper::OnEndChunk(int chunk, io::Printer* p) { + Formatter format(p); if (chunk != limit_chunk_ - 1) { return false; } @@ -510,146 +508,153 @@ bool ColdChunkSkipper::OnEndChunk(int chunk, io::Printer* printer) { return true; } -void MaySetAnnotationVariable(const Options& options, - absl::string_view annotation_name, - absl::string_view injector_template_prefix, - absl::string_view injector_template_suffix, - std::map* variables) { - if (options.field_listener_options.forbidden_field_listener_events.count( - std::string(annotation_name))) - return; - (*variables)[absl::StrCat("annotate_", annotation_name)] = absl::Substitute( - absl::StrCat(injector_template_prefix, injector_template_suffix), - (*variables)["classtype"]); +void AnnotationVar(const Descriptor* desc, const Options& options, + absl::flat_hash_map& vars, + absl::string_view name, absl::string_view val) { + if (!HasTracker(desc, options) || + options.field_listener_options.forbidden_field_listener_events.count( + std::string(absl::StripPrefix(name, "annotate_"))) != 0) { + val = ""; + } + + vars.emplace(name, absl::StrCat(absl::StripAsciiWhitespace(val), "\n")); } -void GenerateExtensionAnnotations( - const Descriptor* descriptor, const Options& options, - std::map* variables) { - const std::map accessor_annotations_to_hooks = { - {"annotate_extension_has", "OnHasExtension"}, - {"annotate_extension_clear", "OnClearExtension"}, - {"annotate_extension_repeated_size", "OnExtensionSize"}, - {"annotate_extension_get", "OnGetExtension"}, - {"annotate_extension_mutable", "OnMutableExtension"}, - {"annotate_extension_set", "OnSetExtension"}, - {"annotate_extension_release", "OnReleaseExtension"}, - {"annotate_repeated_extension_get", "OnGetExtension"}, - {"annotate_repeated_extension_mutable", "OnMutableExtension"}, - {"annotate_repeated_extension_set", "OnSetExtension"}, - {"annotate_repeated_extension_add", "OnAddExtension"}, - {"annotate_repeated_extension_add_mutable", "OnAddMutableExtension"}, - {"annotate_repeated_extension_list", "OnListExtension"}, - {"annotate_repeated_extension_list_mutable", "OnMutableListExtension"}, - }; - for (const auto& annotation : accessor_annotations_to_hooks) { - (*variables)[annotation.first] = ""; - } - if (!HasTracker(descriptor, options)) { - return; - } - absl::string_view tracker = (*variables)["tracker"]; - absl::string_view extensions = (*variables)["extensions"]; - for (const auto& annotation : accessor_annotations_to_hooks) { - const std::string& annotation_name = annotation.first; - const std::string& listener_call = annotation.second; - if (!StrContains(annotation_name, "repeated") && - !StrContains(annotation_name, "size") && - !StrContains(annotation_name, "clear")) { +absl::flat_hash_map ClassVars(const Descriptor* desc, + Options opts) { + absl::flat_hash_map vars = MessageVars(desc); + vars.emplace("classname", ClassName(desc, false)); + vars.emplace("classtype", QualifiedClassName(desc, opts)); + vars.emplace("full_name", desc->full_name()); + vars.emplace("superclass", SuperClassName(desc, opts)); + + for (auto& pair : UnknownFieldsVars(desc, opts)) { + vars.emplace(pair); + } + + AnnotationVar(desc, opts, vars, "annotate_serialize", R"cc( + Impl_::_tracker_.OnSerialize(this); + )cc"); + AnnotationVar(desc, opts, vars, "annotate_deserialize", R"cc( + Impl_::_tracker_.OnDeserialize(this); + )cc"); + // TODO(danilak): Ideally annotate_reflection should not exist and we need + // to annotate all reflective calls on our own, however, as this is a cause + // for side effects, i.e. reading values dynamically, we want the users know + // that dynamic access can happen. + AnnotationVar(desc, opts, vars, "annotate_reflection", R"cc( + Impl_::_tracker_.OnGetMetadata(); + )cc"); + AnnotationVar(desc, opts, vars, "annotate_bytesize", R"cc( + Impl_::_tracker_.OnByteSize(this); + )cc"); + AnnotationVar(desc, opts, vars, "annotate_mergefrom", R"cc( + Impl_::_tracker_.OnMergeFrom(_this, &from); + )cc"); + + static constexpr std::array, + 14> + kVarToHook = {{ + {"annotate_extension_has", "OnHasExtension"}, + {"annotate_extension_clear", "OnClearExtension"}, + {"annotate_extension_repeated_size", "OnExtensionSize"}, + {"annotate_extension_get", "OnGetExtension"}, + {"annotate_extension_mutable", "OnMutableExtension"}, + {"annotate_extension_set", "OnSetExtension"}, + {"annotate_extension_release", "OnReleaseExtension"}, + {"annotate_repeated_extension_get", "OnGetExtension"}, + {"annotate_repeated_extension_mutable", "OnMutableExtension"}, + {"annotate_repeated_extension_set", "OnSetExtension"}, + {"annotate_repeated_extension_add", "OnAddExtension"}, + {"annotate_repeated_extension_add_mutable", "OnAddMutableExtension"}, + {"annotate_repeated_extension_list", "OnListExtension"}, + {"annotate_repeated_extension_list_mutable", + "OnMutableListExtension"}, + }}; + + for (const auto& annotation : kVarToHook) { + vars[annotation.first] = ""; + } + if (!HasTracker(desc, opts)) { + return vars; + } + + absl::string_view extensions = vars["extensions"]; + for (const auto& annotation : kVarToHook) { + absl::string_view name = annotation.first; + absl::string_view call = annotation.second; + + if (!absl::StrContains(name, "repeated") && + !absl::StrContains(name, "size") && !absl::StrContains(name, "clear")) { // Primitive fields accessors. // "Has" is here as users calling "has" on a repeated field is a mistake. - (*variables)[annotation_name] = absl::StrCat( - " ", tracker, ".", listener_call, - "(this, id.number(), _proto_TypeTraits::GetPtr(id.number(), ", - extensions, ", id.default_value_ref()));"); - } else if (StrContains(annotation_name, "repeated") && - !StrContains(annotation_name, "list") && - !StrContains(annotation_name, "size")) { + vars[name] = std::string(absl::StripAsciiWhitespace(absl::Substitute( + R"cc( + Impl_::_tracker_.$0(this, id.number(), + _proto_TypeTraits::GetPtr( + id.number(), $1, id.default_value_ref())); + )cc", + call, extensions))); + continue; + } + + if (absl::StrContains(name, "repeated") && + !absl::StrContains(name, "list") && !absl::StrContains(name, "size")) { // Repeated index accessors. std::string str_index = "index"; - if (StrContains(annotation_name, "add")) { + if (absl::StrContains(name, "add")) { str_index = absl::StrCat(extensions, ".ExtensionSize(id.number()) - 1"); } - (*variables)[annotation_name] = - absl::StrCat(" ", tracker, ".", listener_call, - "(this, id.number(), " - "_proto_TypeTraits::GetPtr(id.number(), ", - extensions, ", ", str_index, "));"); - } else if (StrContains(annotation_name, "list") || - StrContains(annotation_name, "size")) { + vars[name] = std::string(absl::StripAsciiWhitespace(absl::Substitute( + R"cc( + Impl_::_tracker_.$0(this, id.number(), + _proto_TypeTraits::GetPtr(id.number(), $1, $2)); + )cc", + call, extensions, str_index))); + continue; + } + + if (absl::StrContains(name, "list") || absl::StrContains(name, "size")) { // Repeated full accessors. - (*variables)[annotation_name] = absl::StrCat( - " ", tracker, ".", listener_call, - "(this, id.number(), _proto_TypeTraits::GetRepeatedPtr(id.number(), ", - extensions, "));"); - } else { - // Generic accessors such as "clear". - // TODO(b/190614678): Generalize clear from both repeated and non repeated - // calls, currently their underlying memory interfaces are very different. - // Or think of removing clear callback as no usages are needed and no - // memory exist after calling clear(). + vars[name] = std::string(absl::StripAsciiWhitespace(absl::Substitute( + R"cc( + Impl_::_tracker_.$0(this, id.number(), + _proto_TypeTraits::GetRepeatedPtr(id.number(), + $1)); + )cc", + call, extensions))); + continue; } + + // Generic accessors such as "clear". + // TODO(b/190614678): Generalize clear from both repeated and non repeated + // calls, currently their underlying memory interfaces are very different. + // Or think of removing clear callback as no usages are needed and no + // memory exist after calling clear(). } + + return vars; } } // anonymous namespace // =================================================================== -MessageGenerator::MessageGenerator( - const Descriptor* descriptor, - const std::map& vars, int index_in_file_messages, - const Options& options, MessageSCCAnalyzer* scc_analyzer) +MessageGenerator::MessageGenerator(const Descriptor* descriptor, + const std::map&, + int index_in_file_messages, + const Options& options, + MessageSCCAnalyzer* scc_analyzer) : descriptor_(descriptor), index_in_file_messages_(index_in_file_messages), - classname_(ClassName(descriptor, false)), options_(options), field_generators_(descriptor, options, scc_analyzer), - max_has_bit_index_(0), - max_inlined_string_index_(0), - num_weak_fields_(0), - scc_analyzer_(scc_analyzer), - variables_(vars) { - if (!message_layout_helper_) { - message_layout_helper_.reset(new PaddingOptimizer()); - } - SetCommonMessageDataVariables(descriptor, &variables_); - - // Variables that apply to this class - variables_["classname"] = classname_; - variables_["classtype"] = QualifiedClassName(descriptor_, options); - variables_["full_name"] = descriptor_->full_name(); - variables_["superclass"] = SuperClassName(descriptor_, options_); - variables_["annotate_serialize"] = ""; - variables_["annotate_deserialize"] = ""; - variables_["annotate_reflection"] = ""; - variables_["annotate_bytesize"] = ""; - variables_["annotate_mergefrom"] = ""; + scc_analyzer_(scc_analyzer) { - if (HasTracker(descriptor_, options_)) { - const std::string injector_template = - absl::StrCat(" ", variables_["tracker"], "."); - - MaySetAnnotationVariable(options, "serialize", injector_template, - "OnSerialize(this);\n", &variables_); - MaySetAnnotationVariable(options, "deserialize", injector_template, - "OnDeserialize(this);\n", &variables_); - // TODO(danilak): Ideally annotate_reflection should not exist and we need - // to annotate all reflective calls on our own, however, as this is a cause - // for side effects, i.e. reading values dynamically, we want the users know - // that dynamic access can happen. - MaySetAnnotationVariable(options, "reflection", injector_template, - "OnGetMetadata();\n", &variables_); - MaySetAnnotationVariable(options, "bytesize", injector_template, - "OnByteSize(this);\n", &variables_); - MaySetAnnotationVariable(options, "mergefrom", injector_template, - "OnMergeFrom(_this, &from);\n", &variables_); + if (!message_layout_helper_) { + message_layout_helper_ = std::make_unique(); } - GenerateExtensionAnnotations(descriptor_, options_, &variables_); - - SetUnknownFieldsVariable(descriptor_, options_, &variables_); - // Compute optimized field order to be used for layout and initialization // purposes. for (auto field : FieldRange(descriptor_)) { @@ -658,8 +663,11 @@ MessageGenerator::MessageGenerator( } if (IsWeak(field, options_)) { - num_weak_fields_++; - } else if (!field->real_containing_oneof()) { + ++num_weak_fields_; + continue; + } + + if (!field->real_containing_oneof()) { optimized_order_.push_back(field); } } @@ -667,58 +675,25 @@ MessageGenerator::MessageGenerator( message_layout_helper_->OptimizeLayout(&optimized_order_, options_, scc_analyzer_); - // Allocate has_bit_indices_ iff the message has a field that needs hasbits. - int has_bit_fields = 0; + // This message has hasbits iff one or more fields need one. for (auto field : optimized_order_) { if (HasHasbit(field)) { - ++has_bit_fields; if (has_bit_indices_.empty()) { has_bit_indices_.resize(descriptor_->field_count(), kNoHasbit); } - } - } - // For messages with more than 32 has bits, do a first pass which only - // allocates has bits to fields that might be in the fast table. - bool allocated_fast[32] = {}; - if (has_bit_fields > 32) { - for (const auto* field : optimized_order_) { - if (HasHasbit(field)) { - if (!IsDescriptorEligibleForFastParsing(field)) continue; - - // A fast-table with > 16 entries ends up incorporating - // the high-bit for VarInt encoding into the index for the table, - // so we have to incorporate it here also, when computing the - // index likely to be used for that table. - int fast_index = field->number(); - if (fast_index >= 16) fast_index = 16 + (fast_index % 16); - GOOGLE_CHECK_GE(fast_index, 1); - GOOGLE_CHECK_LT(fast_index, 32); - - if (allocated_fast[fast_index]) continue; - allocated_fast[fast_index] = true; - - has_bit_indices_[field->index()] = max_has_bit_index_++; - } - } - } - // Then do a second pass which allocates all remaining has bits - for (const auto* field : optimized_order_) { - if (HasHasbit(field)) { - if (has_bit_indices_[field->index()] == kNoHasbit) { - has_bit_indices_[field->index()] = max_has_bit_index_++; - } + has_bit_indices_[field->index()] = max_has_bit_index_++; } if (IsStringInlined(field, options_)) { if (inlined_string_indices_.empty()) { inlined_string_indices_.resize(descriptor_->field_count(), kNoHasbit); // The bitset[0] is for arena dtor tracking. Donating states start from // bitset[1]; - max_inlined_string_index_++; + ++max_inlined_string_index_; } + inlined_string_indices_[field->index()] = max_inlined_string_index_++; } } - GOOGLE_CHECK_EQ(max_has_bit_index_, has_bit_fields); if (!has_bit_indices_.empty()) { field_generators_.SetHasBitIndices(has_bit_indices_); @@ -728,20 +703,17 @@ MessageGenerator::MessageGenerator( field_generators_.SetInlinedStringIndices(inlined_string_indices_); } - num_required_fields_ = 0; for (int i = 0; i < descriptor->field_count(); i++) { if (descriptor->field(i)->is_required()) { ++num_required_fields_; } } - parse_function_generator_.reset(new ParseFunctionGenerator( + parse_function_generator_ = std::make_unique( descriptor_, max_has_bit_index_, has_bit_indices_, - inlined_string_indices_, options_, scc_analyzer_, variables_)); + inlined_string_indices_, options_, scc_analyzer_, variables_); } -MessageGenerator::~MessageGenerator() = default; - size_t MessageGenerator::HasBitsSize() const { return (max_has_bit_index_ + 31) / 32; } @@ -770,24 +742,24 @@ void MessageGenerator::AddGenerators( std::vector>* extension_generators) { for (int i = 0; i < descriptor_->enum_type_count(); i++) { enum_generators->emplace_back( - new EnumGenerator(descriptor_->enum_type(i), variables_, options_)); + std::make_unique(descriptor_->enum_type(i), options_)); enum_generators_.push_back(enum_generators->back().get()); } for (int i = 0; i < descriptor_->extension_count(); i++) { - extension_generators->emplace_back(new ExtensionGenerator( + extension_generators->emplace_back(std::make_unique( descriptor_->extension(i), options_, scc_analyzer_)); extension_generators_.push_back(extension_generators->back().get()); } } -void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* printer) { - Formatter format(printer, variables_); +void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* p) { + Formatter format(p); // optimized_fields_ does not contain fields where // field->real_containing_oneof() // so we need to iterate over those as well. // // We place the non-oneof fields in optimized_order_, as that controls the - // order of the _has_bits_ entries and we want GDB's pretty printers to be + // order of the _has_bits_ entries and we want GDB's pretty ps to be // able to infer these indices from the k[FIELDNAME]FieldNumber order. std::vector ordered_fields; ordered_fields.reserve(descriptor_->field_count()); @@ -809,7 +781,7 @@ void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* printer) { std::map vars; SetCommonFieldVariables(field, &vars, options_); - format.AddMap(vars); + auto v = p->WithVars(std::move(vars)); format(" ${1$$2$$}$ = $number$,\n", field, FieldConstantName(field)); } format("};\n"); @@ -817,13 +789,7 @@ void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* printer) { for (auto field : ordered_fields) { PrintFieldComment(format, field); - Formatter::SaveState save(&format); - - std::map vars; - SetCommonFieldVariables(field, &vars, options_); - - format.AddMap(vars); - + auto v = p->WithVars(FieldVars(field, options_)); if (field->is_repeated()) { format("$deprecated_attr$int ${1$$name$_size$}$() const$2$\n", field, !IsFieldStripped(field, options_) ? ";" : " {__builtin_trap();}"); @@ -856,7 +822,7 @@ void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* printer) { !IsFieldStripped(field, options_) ? ";" : "{__builtin_trap();}"); // Generate type-specific accessor declarations. - field_generators_.get(field).GenerateAccessorDeclarations(printer); + field_generators_.get(field).GenerateAccessorDeclarations(p); format("\n"); } @@ -1073,8 +1039,10 @@ $annotate_repeated_extension_list_mutable$ for (auto oneof : OneOfRange(descriptor_)) { Formatter::SaveState saver(&format); - format.Set("oneof_name", oneof->name()); - format.Set("camel_oneof_name", UnderscoresToCamelCase(oneof->name(), true)); + auto v = p->WithVars({ + {"oneof_name", oneof->name()}, + {"camel_oneof_name", UnderscoresToCamelCase(oneof->name(), true)}, + }); format( "void ${1$clear_$oneof_name$$}$();\n" "$camel_oneof_name$Case $oneof_name$_case() const;\n", @@ -1083,7 +1051,8 @@ $annotate_repeated_extension_list_mutable$ } void MessageGenerator::GenerateSingularFieldHasBits( - const FieldDescriptor* field, Formatter format) { + const FieldDescriptor* field, io::Printer* p) { + Formatter format(p); if (IsFieldStripped(field, options_)) { format( "inline bool $classname$::has_$name$() const { " @@ -1102,9 +1071,11 @@ void MessageGenerator::GenerateSingularFieldHasBits( int has_bit_index = HasBitIndex(field); GOOGLE_CHECK_NE(has_bit_index, kNoHasbit); - format.Set("has_array_index", has_bit_index / 32); - format.Set("has_mask", - absl::Hex(1u << (has_bit_index % 32), absl::kZeroPad8)); + auto v = p->WithVars({ + {"has_array_index", has_bit_index / 32}, + {"has_mask", absl::Hex(1u << (has_bit_index % 32), absl::kZeroPad8)}, + }); + format( "inline bool $classname$::_internal_has_$name$() const {\n" " bool value = " @@ -1147,12 +1118,14 @@ void MessageGenerator::GenerateSingularFieldHasBits( } } -void MessageGenerator::GenerateOneofHasBits(io::Printer* printer) { - Formatter format(printer, variables_); - for (auto oneof : OneOfRange(descriptor_)) { - format.Set("oneof_name", oneof->name()); - format.Set("oneof_index", oneof->index()); - format.Set("cap_oneof_name", absl::AsciiStrToUpper(oneof->name())); +void MessageGenerator::GenerateOneofHasBits(io::Printer* p) { + Formatter format(p); + for (const auto* oneof : OneOfRange(descriptor_)) { + auto v = p->WithVars({ + {"oneof_index", oneof->index()}, + {"oneof_name", oneof->name()}, + {"cap_oneof_name", absl::AsciiStrToUpper(oneof->name())}, + }); format( "inline bool $classname$::has_$oneof_name$() const {\n" " return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n" @@ -1164,7 +1137,8 @@ void MessageGenerator::GenerateOneofHasBits(io::Printer* printer) { } void MessageGenerator::GenerateOneofMemberHasBits(const FieldDescriptor* field, - const Formatter& format) { + io::Printer* p) { + Formatter format(p); if (IsFieldStripped(field, options_)) { if (HasHasMethod(field)) { format( @@ -1209,7 +1183,8 @@ void MessageGenerator::GenerateOneofMemberHasBits(const FieldDescriptor* field, } void MessageGenerator::GenerateFieldClear(const FieldDescriptor* field, - bool is_inline, Formatter format) { + bool is_inline, io::Printer* p) { + Formatter format(p); if (IsFieldStripped(field, options_)) { format("void $classname$::clear_$name$() { __builtin_trap(); }\n"); return; @@ -1226,9 +1201,10 @@ void MessageGenerator::GenerateFieldClear(const FieldDescriptor* field, if (field->real_containing_oneof()) { // Clear this field only if it is the active field in this oneof, // otherwise ignore + auto v = p->WithVars(OneofFieldVars(field)); format("if (_internal_has_$name$()) {\n"); format.Indent(); - field_generators_.get(field).GenerateClearingCode(format.printer()); + field_generators_.get(field).GenerateClearingCode(p); format("clear_has_$oneof_name$();\n"); format.Outdent(); format("}\n"); @@ -1236,12 +1212,12 @@ void MessageGenerator::GenerateFieldClear(const FieldDescriptor* field, if (ShouldSplit(field, options_)) { format("if (IsSplitMessageDefault()) return;\n"); } - field_generators_.get(field).GenerateClearingCode(format.printer()); + field_generators_.get(field).GenerateClearingCode(p); if (HasHasbit(field)) { int has_bit_index = HasBitIndex(field); - format.Set("has_array_index", has_bit_index / 32); - format.Set("has_mask", - absl::Hex(1u << (has_bit_index % 32), absl::kZeroPad8)); + auto v = p->WithVars({{"has_array_index", has_bit_index / 32}, + {"has_mask", absl::Hex(1u << (has_bit_index % 32), + absl::kZeroPad8)}}); format("$has_bits$[$has_array_index$] &= ~0x$has_mask$u;\n"); } } @@ -1250,8 +1226,8 @@ void MessageGenerator::GenerateFieldClear(const FieldDescriptor* field, format("}\n"); } -void MessageGenerator::GenerateFieldAccessorDefinitions(io::Printer* printer) { - Formatter format(printer, variables_); +void MessageGenerator::GenerateFieldAccessorDefinitions(io::Printer* p) { + Formatter format(p); format("// $classname$\n\n"); for (auto field : FieldRange(descriptor_)) { @@ -1261,12 +1237,7 @@ void MessageGenerator::GenerateFieldAccessorDefinitions(io::Printer* printer) { continue; } - std::map vars; - SetCommonFieldVariables(field, &vars, options_); - - Formatter::SaveState saver(&format); - format.AddMap(vars); - + auto v = p->WithVars(FieldVars(field, options_)); // Generate has_$name$() or $name$_size(). if (field->is_repeated()) { if (IsFieldStripped(field, options_)) { @@ -1288,40 +1259,42 @@ void MessageGenerator::GenerateFieldAccessorDefinitions(io::Printer* printer) { : ""); } } else if (field->real_containing_oneof()) { - format.Set("field_name", UnderscoresToCamelCase(field->name(), true)); - format.Set("oneof_name", field->containing_oneof()->name()); - format.Set("oneof_index", - absl::StrCat(field->containing_oneof()->index())); - GenerateOneofMemberHasBits(field, format); + auto v = p->WithVars({ + {"field_name", UnderscoresToCamelCase(field->name(), true)}, + {"oneof_name", field->containing_oneof()->name()}, + {"oneof_index", absl::StrCat(field->containing_oneof()->index())}, + }); + GenerateOneofMemberHasBits(field, p); } else { // Singular field. - GenerateSingularFieldHasBits(field, format); + GenerateSingularFieldHasBits(field, p); } if (!IsCrossFileMaybeMap(field)) { - GenerateFieldClear(field, true, format); + GenerateFieldClear(field, true, p); } // Generate type-specific accessors. if (!IsFieldStripped(field, options_)) { - field_generators_.get(field).GenerateInlineAccessorDefinitions(printer); + field_generators_.get(field).GenerateInlineAccessorDefinitions(p); } format("\n"); } // Generate has_$name$() and clear_has_$name$() functions for oneofs. - GenerateOneofHasBits(printer); + GenerateOneofHasBits(p); } -void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { - Formatter format(printer, variables_); +void MessageGenerator::GenerateClassDefinition(io::Printer* p) { + auto v = p->WithVars(ClassVars(descriptor_, options_)); + Formatter format(p); if (IsMapEntryMessage(descriptor_)) { std::map vars; CollectMapInfo(options_, descriptor_, &vars); vars["lite"] = HasDescriptorMethods(descriptor_->file(), options_) ? "" : "Lite"; - format.AddMap(vars); + auto v = p->WithVars(std::move(vars)); format( "class $classname$ : public " "::$proto_ns$::internal::MapEntry$lite$<$classname$, \n" @@ -1638,9 +1611,9 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { // For instances that derive from Message (rather than MessageLite), some // methods are virtual and should be marked as final. - format.Set("full_final", HasDescriptorMethods(descriptor_->file(), options_) - ? "final" - : ""); + auto v2 = p->WithVars( + {{"full_final", + HasDescriptorMethods(descriptor_->file(), options_) ? "final" : ""}}); if (HasGeneratedMethods(descriptor_->file(), options_)) { if (HasDescriptorMethods(descriptor_->file(), options_)) { @@ -1690,7 +1663,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { "\n" "size_t ByteSizeLong() const final;\n"); - parse_function_generator_->GenerateMethodDecls(printer); + parse_function_generator_->GenerateMethodDecls(p); format( "$uint8$* _InternalSerialize(\n" @@ -1797,8 +1770,9 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { for (int i = 0; i < descriptor_->nested_type_count(); i++) { const Descriptor* nested_type = descriptor_->nested_type(i); if (!IsMapEntryMessage(nested_type)) { - format.Set("nested_full_name", ClassName(nested_type, false)); - format.Set("nested_name", ResolveKeyword(nested_type->name())); + auto v = + p->WithVars({{"nested_full_name", ClassName(nested_type, false)}, + {"nested_name", ResolveKeyword(nested_type->name())}}); format("typedef ${1$$nested_full_name$$}$ ${1$$nested_name$$}$;\n", nested_type); } @@ -1811,7 +1785,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { // Import all nested enums and their values into this class's scope with // typedefs and constants. for (int i = 0; i < descriptor_->enum_type_count(); i++) { - enum_generators_[i]->GenerateSymbolImports(printer); + enum_generators_[i]->GenerateSymbolImports(p); format("\n"); } @@ -1820,11 +1794,11 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { "\n"); // Generate accessor methods for all fields. - GenerateFieldAccessorDeclarations(printer); + GenerateFieldAccessorDeclarations(p); // Declare extension identifiers. for (int i = 0; i < descriptor_->extension_count(); i++) { - extension_generators_[i]->GenerateDeclaration(printer); + extension_generators_[i]->GenerateDeclaration(p); } @@ -1863,7 +1837,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { } if (HasGeneratedMethods(descriptor_->file(), options_)) { - parse_function_generator_->GenerateDataDecls(printer); + parse_function_generator_->GenerateDataDecls(p); } // Prepare decls for _cached_size_ and _has_bits_. Their position in the @@ -1932,9 +1906,9 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { // Emit some private and static members for (auto field : optimized_order_) { const FieldGenerator& generator = field_generators_.get(field); - generator.GenerateStaticMembers(printer); + generator.GenerateStaticMembers(p); if (!ShouldSplit(field, options_)) { - generator.GeneratePrivateMembers(printer); + generator.GeneratePrivateMembers(p); } } if (ShouldSplit(descriptor_, options_)) { @@ -1943,7 +1917,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { for (auto field : optimized_order_) { if (!ShouldSplit(field, options_)) continue; const FieldGenerator& generator = field_generators_.get(field); - generator.GeneratePrivateMembers(printer); + generator.GeneratePrivateMembers(p); } format.Outdent(); format( @@ -1968,14 +1942,14 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { camel_oneof_name); for (auto field : FieldRange(oneof)) { if (!IsFieldStripped(field, options_)) { - field_generators_.get(field).GeneratePrivateMembers(printer); + field_generators_.get(field).GeneratePrivateMembers(p); } } format.Outdent(); format("} $1$_;\n", oneof->name()); for (auto field : FieldRange(oneof)) { if (!IsFieldStripped(field, options_)) { - field_generators_.get(field).GenerateStaticMembers(printer); + field_generators_.get(field).GenerateStaticMembers(p); } } } @@ -2025,16 +1999,19 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { GOOGLE_DCHECK(!need_to_emit_cached_size); } // NOLINT(readability/fn_size) -void MessageGenerator::GenerateInlineMethods(io::Printer* printer) { +void MessageGenerator::GenerateInlineMethods(io::Printer* p) { + auto v = p->WithVars(ClassVars(descriptor_, options_)); if (IsMapEntryMessage(descriptor_)) return; - GenerateFieldAccessorDefinitions(printer); + GenerateFieldAccessorDefinitions(p); // Generate oneof_case() functions. for (auto oneof : OneOfRange(descriptor_)) { - Formatter format(printer, variables_); - format.Set("camel_oneof_name", UnderscoresToCamelCase(oneof->name(), true)); - format.Set("oneof_name", oneof->name()); - format.Set("oneof_index", oneof->index()); + Formatter format(p); + auto v = p->WithVars({ + {"camel_oneof_name", UnderscoresToCamelCase(oneof->name(), true)}, + {"oneof_name", oneof->name()}, + {"oneof_index", oneof->index()}, + }); format( "inline $classname$::$camel_oneof_name$Case $classname$::" "${1$$oneof_name$_case$}$() const {\n" @@ -2045,9 +2022,10 @@ void MessageGenerator::GenerateInlineMethods(io::Printer* printer) { } } -void MessageGenerator::GenerateSchema(io::Printer* printer, int offset, +void MessageGenerator::GenerateSchema(io::Printer* p, int offset, int has_offset) { - Formatter format(printer, variables_); + auto v = p->WithVars(ClassVars(descriptor_, options_)); + Formatter format(p); has_offset = !has_bit_indices_.empty() || IsMapEntryMessage(descriptor_) ? offset + has_offset : -1; @@ -2063,8 +2041,9 @@ void MessageGenerator::GenerateSchema(io::Printer* printer, int offset, inlined_string_indices_offset); } -void MessageGenerator::GenerateClassMethods(io::Printer* printer) { - Formatter format(printer, variables_); +void MessageGenerator::GenerateClassMethods(io::Printer* p) { + auto v = p->WithVars(ClassVars(descriptor_, options_)); + Formatter format(p); if (IsMapEntryMessage(descriptor_)) { format( "$classname$::$classname$() {}\n" @@ -2133,7 +2112,7 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { " PROTOBUF_FIELD_OFFSET($classtype$, $oneof_case$);\n"); } for (auto field : FieldRange(descriptor_)) { - field_generators_.get(field).GenerateInternalAccessorDeclarations(printer); + field_generators_.get(field).GenerateInternalAccessorDeclarations(p); if (IsFieldStripped(field, options_)) { continue; } @@ -2161,7 +2140,7 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { format("};\n\n"); for (auto field : FieldRange(descriptor_)) { if (!IsFieldStripped(field, options_)) { - field_generators_.get(field).GenerateInternalAccessorDefinitions(printer); + field_generators_.get(field).GenerateInternalAccessorDefinitions(p); } } @@ -2170,54 +2149,49 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { if (IsFieldStripped(field, options_)) { continue; } - field_generators_.get(field).GenerateNonInlineAccessorDefinitions(printer); + field_generators_.get(field).GenerateNonInlineAccessorDefinitions(p); if (IsCrossFileMaybeMap(field)) { - Formatter::SaveState saver(&format); - std::map vars; - SetCommonFieldVariables(field, &vars, options_); - if (field->real_containing_oneof()) { - SetCommonOneofFieldVariables(field, &vars); - } - format.AddMap(vars); - GenerateFieldClear(field, false, format); + auto v1 = p->WithVars(FieldVars(field, options_)); + auto v2 = p->WithVars(OneofFieldVars(field)); + GenerateFieldClear(field, false, p); } } - GenerateStructors(printer); + GenerateStructors(p); format("\n"); if (descriptor_->real_oneof_decl_count() > 0) { - GenerateOneofClear(printer); + GenerateOneofClear(p); format("\n"); } if (HasGeneratedMethods(descriptor_->file(), options_)) { - GenerateClear(printer); + GenerateClear(p); format("\n"); if (!HasSimpleBaseClass(descriptor_, options_)) { - parse_function_generator_->GenerateMethodImpls(printer); + parse_function_generator_->GenerateMethodImpls(p); format("\n"); - parse_function_generator_->GenerateDataDefinitions(printer); + parse_function_generator_->GenerateDataDefinitions(p); } - GenerateSerializeWithCachedSizesToArray(printer); + GenerateSerializeWithCachedSizesToArray(p); format("\n"); - GenerateByteSize(printer); + GenerateByteSize(p); format("\n"); - GenerateMergeFrom(printer); + GenerateMergeFrom(p); format("\n"); - GenerateClassSpecificMergeImpl(printer); + GenerateClassSpecificMergeImpl(p); format("\n"); - GenerateCopyFrom(printer); + GenerateCopyFrom(p); format("\n"); - GenerateIsInitialized(printer); + GenerateIsInitialized(p); format("\n"); } @@ -2235,9 +2209,9 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { DefaultInstanceName(descriptor_, options_, /*split=*/false)); } - GenerateVerify(printer); + GenerateVerify(p); - GenerateSwap(printer); + GenerateSwap(p); format("\n"); if (HasDescriptorMethods(descriptor_->file(), options_)) { @@ -2275,9 +2249,9 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { } } -std::pair MessageGenerator::GenerateOffsets( - io::Printer* printer) { - Formatter format(printer, variables_); +std::pair MessageGenerator::GenerateOffsets(io::Printer* p) { + auto v = p->WithVars(ClassVars(descriptor_, options_)); + Formatter format(p); if (!has_bit_indices_.empty() || IsMapEntryMessage(descriptor_)) { format("PROTOBUF_FIELD_OFFSET($classtype$, $has_bits$),\n"); @@ -2393,9 +2367,9 @@ std::pair MessageGenerator::GenerateOffsets( return std::make_pair(entries, offsets); } -void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) { +void MessageGenerator::GenerateSharedConstructorCode(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; - Formatter format(printer, variables_); + Formatter format(p); format( "inline void $classname$::SharedCtor(\n" @@ -2441,7 +2415,7 @@ void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) { continue; } put_sep(); - field_generators_.get(field).GenerateAggregateInitializer(printer); + field_generators_.get(field).GenerateAggregateInitializer(p); } if (ShouldSplit(descriptor_, options_)) { put_sep(); @@ -2511,7 +2485,7 @@ void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) { if (ShouldSplit(field, options_)) { continue; } - field_generators_.get(field).GenerateConstructorCode(printer); + field_generators_.get(field).GenerateConstructorCode(p); } if (ShouldForceAllocationOnConstruction(descriptor_, options_)) { @@ -2529,10 +2503,11 @@ void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) { format("}\n\n"); } -void MessageGenerator::GenerateInitDefaultSplitInstance(io::Printer* printer) { +void MessageGenerator::GenerateInitDefaultSplitInstance(io::Printer* p) { if (!ShouldSplit(descriptor_, options_)) return; - Formatter format(printer, variables_); + auto v = p->WithVars(ClassVars(descriptor_, options_)); + Formatter format(p); const char* field_sep = " "; const auto put_sep = [&] { format("\n$1$ ", field_sep); @@ -2541,15 +2516,14 @@ void MessageGenerator::GenerateInitDefaultSplitInstance(io::Printer* printer) { for (const auto* field : optimized_order_) { if (ShouldSplit(field, options_)) { put_sep(); - field_generators_.get(field).GenerateConstexprAggregateInitializer( - printer); + field_generators_.get(field).GenerateConstexprAggregateInitializer(p); } } } -void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) { +void MessageGenerator::GenerateSharedDestructorCode(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; - Formatter format(printer, variables_); + Formatter format(p); format("inline void $classname$::SharedDtor() {\n"); format.Indent(); @@ -2565,7 +2539,7 @@ void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) { if (ShouldSplit(field, options_)) { continue; } - field_generators_.get(field).GenerateDestructorCode(printer); + field_generators_.get(field).GenerateDestructorCode(p); } if (ShouldSplit(descriptor_, options_)) { format("if (!IsSplitMessageDefault()) {\n"); @@ -2573,7 +2547,7 @@ void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) { format("auto* $cached_split_ptr$ = $split$;\n"); for (auto field : optimized_order_) { if (ShouldSplit(field, options_)) { - field_generators_.get(field).GenerateDestructorCode(printer); + field_generators_.get(field).GenerateDestructorCode(p); } } format("delete $cached_split_ptr$;\n"); @@ -2615,10 +2589,10 @@ ArenaDtorNeeds MessageGenerator::NeedsArenaDestructor() const { return needs; } -void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) { +void MessageGenerator::GenerateArenaDestructorCode(io::Printer* p) { GOOGLE_CHECK(NeedsArenaDestructor() > ArenaDtorNeeds::kNone); - Formatter format(printer, variables_); + Formatter format(p); // Generate the ArenaDtor() method. Track whether any fields actually produced // code that needs to be called. @@ -2636,7 +2610,7 @@ void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) { if (IsFieldStripped(field, options_) || ShouldSplit(field, options_)) continue; const FieldGenerator& fg = field_generators_.get(field); - fg.GenerateArenaDestructorCode(printer); + fg.GenerateArenaDestructorCode(p); } if (ShouldSplit(descriptor_, options_)) { format("if (!_this->IsSplitMessageDefault()) {\n"); @@ -2645,7 +2619,7 @@ void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) { if (IsFieldStripped(field, options_) || !ShouldSplit(field, options_)) continue; const FieldGenerator& fg = field_generators_.get(field); - fg.GenerateArenaDestructorCode(printer); + fg.GenerateArenaDestructorCode(p); } format.Outdent(); format("}\n"); @@ -2655,7 +2629,7 @@ void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) { for (auto oneof : OneOfRange(descriptor_)) { for (auto field : FieldRange(oneof)) { if (IsFieldStripped(field, options_)) continue; - field_generators_.get(field).GenerateArenaDestructorCode(printer); + field_generators_.get(field).GenerateArenaDestructorCode(p); } } @@ -2663,8 +2637,9 @@ void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) { format("}\n"); } -void MessageGenerator::GenerateConstexprConstructor(io::Printer* printer) { - Formatter format(printer, variables_); +void MessageGenerator::GenerateConstexprConstructor(io::Printer* p) { + auto v = p->WithVars(ClassVars(descriptor_, options_)); + Formatter format(p); if (IsMapEntryMessage(descriptor_) || !HasImplData(descriptor_, options_)) { format( @@ -2707,7 +2682,7 @@ void MessageGenerator::GenerateConstexprConstructor(io::Printer* printer) { continue; } put_sep(); - field_generators_.get(field).GenerateConstexprAggregateInitializer(printer); + field_generators_.get(field).GenerateConstexprAggregateInitializer(p); } if (ShouldSplit(descriptor_, options_)) { put_sep(); @@ -2746,8 +2721,8 @@ void MessageGenerator::GenerateConstexprConstructor(io::Printer* printer) { format("} {}\n"); } -void MessageGenerator::GenerateCopyConstructorBody(io::Printer* printer) const { - Formatter format(printer, variables_); +void MessageGenerator::GenerateCopyConstructorBody(io::Printer* p) const { + Formatter format(p); const RunMap runs = FindRuns(optimized_order_, [this](const FieldDescriptor* field) { @@ -2783,15 +2758,16 @@ void MessageGenerator::GenerateCopyConstructorBody(io::Printer* printer) const { const std::string last_field_name = FieldMemberName(optimized_order_[i + run_length - 1], /*cold=*/false); - format.Set("first", first_field_name); - format.Set("last", last_field_name); - + auto v = p->WithVars({ + {"first", first_field_name}, + {"last", last_field_name}, + }); format(pod_template.c_str()); i += run_length - 1; // ++i at the top of the loop. } else { - field_generators_.get(field).GenerateCopyConstructorCode(printer); + field_generators_.get(field).GenerateCopyConstructorCode(p); } } @@ -2802,7 +2778,7 @@ void MessageGenerator::GenerateCopyConstructorBody(io::Printer* printer) const { // TODO(b/122856539): cache the split pointers. for (auto field : optimized_order_) { if (ShouldSplit(field, options_)) { - field_generators_.get(field).GenerateCopyConstructorCode(printer); + field_generators_.get(field).GenerateCopyConstructorCode(p); } } format.Outdent(); @@ -2810,8 +2786,8 @@ void MessageGenerator::GenerateCopyConstructorBody(io::Printer* printer) const { } } -void MessageGenerator::GenerateStructors(io::Printer* printer) { - Formatter format(printer, variables_); +void MessageGenerator::GenerateStructors(io::Printer* p) { + Formatter format(p); format( "$classname$::$classname$(::$proto_ns$::Arena* arena,\n" @@ -2832,9 +2808,30 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { " // @@protoc_insertion_point(arena_constructor:$full_name$)\n" "}\n"); - std::map vars; - SetUnknownFieldsVariable(descriptor_, options_, &vars); - format.AddMap(vars); + // If the message contains only scalar fields (ints and enums), + // then we can copy the entire impl_ section with a single statement. + bool copy_construct_impl = + !ShouldSplit(descriptor_, options_) && + !HasSimpleBaseClass(descriptor_, options_) && + (descriptor_->extension_range_count() == 0 && + descriptor_->real_oneof_decl_count() == 0 && num_weak_fields_ == 0); + for (const auto& field : optimized_order_) { + if (!copy_construct_impl) break; + if (field->is_repeated() || field->is_extension()) { + copy_construct_impl = false; + } else if (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM && + field->cpp_type() != FieldDescriptor::CPPTYPE_INT32 && + field->cpp_type() != FieldDescriptor::CPPTYPE_INT64 && + field->cpp_type() != FieldDescriptor::CPPTYPE_UINT32 && + field->cpp_type() != FieldDescriptor::CPPTYPE_UINT64 && + field->cpp_type() != FieldDescriptor::CPPTYPE_FLOAT && + field->cpp_type() != FieldDescriptor::CPPTYPE_DOUBLE && + field->cpp_type() != FieldDescriptor::CPPTYPE_BOOL) { + copy_construct_impl = false; + } else { + // non-repeated integer fields are fine to copy en masse. + } + } // Generate the copy constructor. if (UsingImplicitWeakFields(descriptor_->file(), options_)) { @@ -2847,6 +2844,16 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { " : $classname$() {\n" " MergeFrom(from);\n" "}\n"); + } else if (copy_construct_impl) { + format( + "$classname$::$classname$(const $classname$& from)\n" + " : $superclass$(), _impl_(from._impl_) {\n" + " _internal_metadata_.MergeFrom<$unknown_fields_type$>(\n" + " from._internal_metadata_);\n"); + format( + " // @@protoc_insertion_point(copy_constructor:$full_name$)\n" + "}\n" + "\n"); } else { format( "$classname$::$classname$(const $classname$& from)\n" @@ -2892,7 +2899,7 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { continue; } put_sep(); - field_generators_.get(field).GenerateCopyAggregateInitializer(printer); + field_generators_.get(field).GenerateCopyAggregateInitializer(p); } if (ShouldSplit(descriptor_, options_)) { put_sep(); @@ -2938,7 +2945,7 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { "from.$extensions$);\n"); } - GenerateCopyConstructorBody(printer); + GenerateCopyConstructorBody(p); // Copy oneof fields. Oneof field requires oneof case check. for (auto oneof : OneOfRange(descriptor_)) { @@ -2951,7 +2958,7 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); format.Indent(); if (!IsFieldStripped(field, options_)) { - field_generators_.get(field).GenerateMergingCode(printer); + field_generators_.get(field).GenerateMergingCode(p); } format("break;\n"); format.Outdent(); @@ -2974,7 +2981,7 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { } // Generate the shared constructor code. - GenerateSharedConstructorCode(printer); + GenerateSharedConstructorCode(p); // Generate the destructor. if (!HasSimpleBaseClass(descriptor_, options_)) { @@ -3004,11 +3011,11 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { } // Generate the shared destructor code. - GenerateSharedDestructorCode(printer); + GenerateSharedDestructorCode(p); // Generate the arena-specific destructor code. if (NeedsArenaDestructor() > ArenaDtorNeeds::kNone) { - GenerateArenaDestructorCode(printer); + GenerateArenaDestructorCode(p); } if (!HasSimpleBaseClass(descriptor_, options_)) { @@ -3020,8 +3027,9 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { } } -void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* printer) { - Formatter format(printer, variables_); +void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* p) { + auto v = p->WithVars(ClassVars(descriptor_, options_)); + Formatter format(p); format( "template<> " "PROTOBUF_NOINLINE $classtype$*\n" @@ -3030,9 +3038,9 @@ void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* printer) { "}\n"); } -void MessageGenerator::GenerateClear(io::Printer* printer) { +void MessageGenerator::GenerateClear(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; - Formatter format(printer, variables_); + Formatter format(p); // The maximum number of bytes we will memset to zero without checking their // hasbit to see if a zero-init is necessary. @@ -3087,7 +3095,7 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { bool first_split_chunk_processed = false; for (size_t chunk_index = 0; chunk_index < chunks.size(); chunk_index++) { std::vector& chunk = chunks[chunk_index]; - cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "", printer); + cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "", p); const FieldDescriptor* memset_start = nullptr; const FieldDescriptor* memset_end = nullptr; @@ -3146,8 +3154,7 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { if (memset_start) { if (memset_start == memset_end) { // For clarity, do not memset a single field. - field_generators_.get(memset_start) - .GenerateMessageClearingCode(printer); + field_generators_.get(memset_start).GenerateMessageClearingCode(p); } else { GOOGLE_CHECK_EQ(chunk_is_split, ShouldSplit(memset_start, options_)); GOOGLE_CHECK_EQ(chunk_is_split, ShouldSplit(memset_end, options_)); @@ -3173,11 +3180,10 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { field->cpp_type() == FieldDescriptor::CPPTYPE_STRING); if (have_enclosing_if) { - PrintPresenceCheck(format, field, has_bit_indices_, printer, - &cached_has_word_index); + PrintPresenceCheck(field, has_bit_indices_, p, &cached_has_word_index); } - field_generators_.get(field).GenerateMessageClearingCode(printer); + field_generators_.get(field).GenerateMessageClearingCode(p); if (have_enclosing_if) { format.Outdent(); @@ -3197,7 +3203,7 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { } } - if (cold_skipper.OnEndChunk(chunk_index, printer)) { + if (cold_skipper.OnEndChunk(chunk_index, p)) { // Reset here as it may have been updated in just closed if statement. cached_has_word_index = -1; } @@ -3219,21 +3225,18 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { format("$has_bits$.Clear();\n"); } - std::map vars; - SetUnknownFieldsVariable(descriptor_, options_, &vars); - format.AddMap(vars); format("_internal_metadata_.Clear<$unknown_fields_type$>();\n"); format.Outdent(); format("}\n"); } -void MessageGenerator::GenerateOneofClear(io::Printer* printer) { +void MessageGenerator::GenerateOneofClear(io::Printer* p) { // Generated function clears the active field and union case (e.g. foo_case_). int i = 0; for (auto oneof : OneOfRange(descriptor_)) { - Formatter format(printer, variables_); - format.Set("oneofname", oneof->name()); + Formatter format(p); + auto v = p->WithVars({{"oneofname", oneof->name()}}); format( "void $classname$::clear_$oneofname$() {\n" @@ -3248,7 +3251,7 @@ void MessageGenerator::GenerateOneofClear(io::Printer* printer) { if (!IsStringOrMessage(field) || IsFieldStripped(field, options_)) { format("// No need to clear\n"); } else { - field_generators_.get(field).GenerateClearingCode(printer); + field_generators_.get(field).GenerateClearingCode(p); } format("break;\n"); format.Outdent(); @@ -3272,9 +3275,9 @@ void MessageGenerator::GenerateOneofClear(io::Printer* printer) { } } -void MessageGenerator::GenerateSwap(io::Printer* printer) { +void MessageGenerator::GenerateSwap(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; - Formatter format(printer, variables_); + Formatter format(p); format("void $classname$::InternalSwap($classname$* other) {\n"); format.Indent(); @@ -3287,9 +3290,6 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) { "\n"); } - std::map vars; - SetUnknownFieldsVariable(descriptor_, options_, &vars); - format.AddMap(vars); if (HasNonSplitOptionalString(descriptor_, options_)) { format( "auto* lhs_arena = GetArenaForAllocation();\n" @@ -3328,8 +3328,10 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) { const std::string last_field_name = FieldMemberName( optimized_order_[i + run_length - 1], /*cold=*/false); - format.Set("first", first_field_name); - format.Set("last", last_field_name); + auto v = p->WithVars({ + {"first", first_field_name}, + {"last", last_field_name}, + }); format( "::PROTOBUF_NAMESPACE_ID::internal::memswap<\n" @@ -3342,7 +3344,7 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) { i += run_length - 1; // ++i at the top of the loop. } else { - field_generators_.get(field).GenerateSwappingCode(printer); + field_generators_.get(field).GenerateSwappingCode(p); } } if (ShouldSplit(descriptor_, options_)) { @@ -3379,8 +3381,8 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) { format("}\n"); } -void MessageGenerator::GenerateMergeFrom(io::Printer* printer) { - Formatter format(printer, variables_); +void MessageGenerator::GenerateMergeFrom(io::Printer* p) { + Formatter format(p); if (!HasSimpleBaseClass(descriptor_, options_)) { if (HasDescriptorMethods(descriptor_->file(), options_)) { // We don't override the generalized MergeFrom (aka that which @@ -3426,10 +3428,10 @@ void MessageGenerator::GenerateMergeFrom(io::Printer* printer) { } } -void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { +void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; // Generate the class-specific MergeFrom, which avoids the GOOGLE_CHECK and cast. - Formatter format(printer, variables_); + Formatter format(p); if (!HasDescriptorMethods(descriptor_->file(), options_)) { // For messages that don't inherit from Message, just implement MergeFrom // directly. @@ -3480,8 +3482,7 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { const std::vector& chunk = chunks[chunk_index]; bool have_outer_if = chunk.size() > 1 && HasByteIndex(chunk.front()) != kNoHasbit; - cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "from.", - printer); + cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "from.", p); if (have_outer_if) { // Emit an if() that will let us skip the whole chunk if none are set. @@ -3511,13 +3512,13 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { const FieldGenerator& generator = field_generators_.get(field); if (field->is_repeated()) { - generator.GenerateMergingCode(printer); + generator.GenerateMergingCode(p); } else if (field->is_optional() && !HasHasbit(field)) { // Merge semantics without true field presence: primitive fields are // merged only if non-zero (numeric) or non-empty (string). bool have_enclosing_if = - EmitFieldNonDefaultCondition(printer, "from.", field); - generator.GenerateMergingCode(printer); + EmitFieldNonDefaultCondition(p, "from.", field); + generator.GenerateMergingCode(p); if (have_enclosing_if) { format.Outdent(); format("}\n"); @@ -3528,7 +3529,7 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { GOOGLE_CHECK(HasHasbit(field)); format("if (from._internal_has_$1$()) {\n", FieldName(field)); format.Indent(); - generator.GenerateMergingCode(printer); + generator.GenerateMergingCode(p); format.Outdent(); format("}\n"); } else { @@ -3544,9 +3545,9 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { // Defer hasbit modification until the end of chunk. // This can reduce the number of loads/stores by up to 7 per 8 fields. deferred_has_bit_changes = true; - generator.GenerateCopyConstructorCode(printer); + generator.GenerateCopyConstructorCode(p); } else { - generator.GenerateMergingCode(printer); + generator.GenerateMergingCode(p); } format.Outdent(); @@ -3566,7 +3567,7 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { format("}\n"); } - if (cold_skipper.OnEndChunk(chunk_index, printer)) { + if (cold_skipper.OnEndChunk(chunk_index, p)) { // Reset here as it may have been updated in just closed if statement. cached_has_word_index = -1; } @@ -3580,7 +3581,7 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); format.Indent(); if (!IsFieldStripped(field, options_)) { - field_generators_.get(field).GenerateMergingCode(printer); + field_generators_.get(field).GenerateMergingCode(p); } format("break;\n"); format.Outdent(); @@ -3617,9 +3618,9 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { format("}\n"); } -void MessageGenerator::GenerateCopyFrom(io::Printer* printer) { +void MessageGenerator::GenerateCopyFrom(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; - Formatter format(printer, variables_); + Formatter format(p); if (HasDescriptorMethods(descriptor_->file(), options_)) { // We don't override the generalized CopyFrom (aka that which // takes in the Message base class as a parameter); instead we just @@ -3678,15 +3679,15 @@ void MessageGenerator::GenerateCopyFrom(io::Printer* printer) { format("}\n"); } -void MessageGenerator::GenerateVerify(io::Printer* printer) { +void MessageGenerator::GenerateVerify(io::Printer* p) { } void MessageGenerator::GenerateSerializeOneofFields( - io::Printer* printer, const std::vector& fields) { - Formatter format(printer, variables_); + io::Printer* p, const std::vector& fields) { + Formatter format(p); GOOGLE_CHECK(!fields.empty()); if (fields.size() == 1) { - GenerateSerializeOneField(printer, fields[0], -1); + GenerateSerializeOneField(p, fields[0], -1); return; } // We have multiple mutually exclusive choices. Emit a switch statement. @@ -3696,8 +3697,7 @@ void MessageGenerator::GenerateSerializeOneofFields( for (auto field : fields) { format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); format.Indent(); - field_generators_.get(field).GenerateSerializeWithCachedSizesToArray( - printer); + field_generators_.get(field).GenerateSerializeWithCachedSizesToArray(p); format("break;\n"); format.Outdent(); format("}\n"); @@ -3709,10 +3709,10 @@ void MessageGenerator::GenerateSerializeOneofFields( "}\n"); } -void MessageGenerator::GenerateSerializeOneField(io::Printer* printer, +void MessageGenerator::GenerateSerializeOneField(io::Printer* p, const FieldDescriptor* field, int cached_has_bits_index) { - Formatter format(printer, variables_); + Formatter format(p); if (!field->options().weak()) { // For weakfields, PrintFieldComment is called during iteration. PrintFieldComment(format, field); @@ -3735,10 +3735,10 @@ void MessageGenerator::GenerateSerializeOneField(io::Printer* printer, format.Indent(); have_enclosing_if = true; } else if (field->is_optional() && !HasHasbit(field)) { - have_enclosing_if = EmitFieldNonDefaultCondition(printer, "this->", field); + have_enclosing_if = EmitFieldNonDefaultCondition(p, "this->", field); } - field_generators_.get(field).GenerateSerializeWithCachedSizesToArray(printer); + field_generators_.get(field).GenerateSerializeWithCachedSizesToArray(p); if (have_enclosing_if) { format.Outdent(); @@ -3748,21 +3748,20 @@ void MessageGenerator::GenerateSerializeOneField(io::Printer* printer, } void MessageGenerator::GenerateSerializeOneExtensionRange( - io::Printer* printer, const Descriptor::ExtensionRange* range) { + io::Printer* p, const Descriptor::ExtensionRange* range) { std::map vars = variables_; vars["start"] = absl::StrCat(range->start); vars["end"] = absl::StrCat(range->end); - Formatter format(printer, vars); + Formatter format(p, vars); format("// Extension range [$start$, $end$)\n"); format( "target = $extensions$._InternalSerialize(\n" "internal_default_instance(), $start$, $end$, target, stream);\n\n"); } -void MessageGenerator::GenerateSerializeWithCachedSizesToArray( - io::Printer* printer) { +void MessageGenerator::GenerateSerializeWithCachedSizesToArray(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; - Formatter format(printer, variables_); + Formatter format(p); if (descriptor_->options().message_set_wire_format()) { // Special-case MessageSet. format( @@ -3773,9 +3772,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesToArray( " target = $extensions$." "InternalSerializeMessageSetWithCachedSizesToArray(\n" // "internal_default_instance(), target, stream);\n"); - std::map vars; - SetUnknownFieldsVariable(descriptor_, options_, &vars); - format.AddMap(vars); + format( " target = ::_pbi::" "InternalSerializeUnknownMessageSetItemsToArray(\n" @@ -3801,14 +3798,14 @@ void MessageGenerator::GenerateSerializeWithCachedSizesToArray( format.Indent(); } - GenerateSerializeWithCachedSizesBody(printer); + GenerateSerializeWithCachedSizesBody(p); if (!ShouldSerializeInOrder(descriptor_, options_)) { format.Outdent(); format("#else // NDEBUG\n"); format.Indent(); - GenerateSerializeWithCachedSizesBodyShuffled(printer); + GenerateSerializeWithCachedSizesBodyShuffled(p); format.Outdent(); format("#endif // !NDEBUG\n"); @@ -3823,10 +3820,9 @@ void MessageGenerator::GenerateSerializeWithCachedSizesToArray( "}\n"); } -void MessageGenerator::GenerateSerializeWithCachedSizesBody( - io::Printer* printer) { +void MessageGenerator::GenerateSerializeWithCachedSizesBody(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; - Formatter format(printer, variables_); + Formatter format(p); // If there are multiple fields in a row from the same oneof then we // coalesce them and emit a switch statement. This is more efficient // because it lets the C++ compiler know this is a "at most one can happen" @@ -3834,9 +3830,9 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( // compiler's emitted code might check has_y() even when has_x() is true. class LazySerializerEmitter { public: - LazySerializerEmitter(MessageGenerator* mg, io::Printer* printer) + LazySerializerEmitter(MessageGenerator* mg, io::Printer* p) : mg_(mg), - format_(printer), + p_(p), eager_(IsProto3(mg->descriptor_->file())), cached_has_bit_index_(kNoHasbit) {} @@ -3845,6 +3841,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( // If conditions allow, try to accumulate a run of fields from the same // oneof, and handle them at the next Flush(). void Emit(const FieldDescriptor* field) { + Formatter format(p_); if (eager_ || MustFlush(field)) { Flush(); } @@ -3860,14 +3857,13 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( // Reload. int new_index = has_bit_index / 32; - format_("cached_has_bits = _impl_._has_bits_[$1$];\n", new_index); + format("cached_has_bits = _impl_._has_bits_[$1$];\n", new_index); cached_has_bit_index_ = new_index; } } - mg_->GenerateSerializeOneField(format_.printer(), field, - cached_has_bit_index_); + mg_->GenerateSerializeOneField(p_, field, cached_has_bit_index_); } else { v_.push_back(field); } @@ -3881,7 +3877,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( void Flush() { if (!v_.empty()) { - mg_->GenerateSerializeOneofFields(format_.printer(), v_); + mg_->GenerateSerializeOneofFields(p_, v_); v_.clear(); } } @@ -3895,8 +3891,8 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( } MessageGenerator* mg_; - Formatter format_; - const bool eager_; + io::Printer* p_; + bool eager_; std::vector v_; // cached_has_bit_index_ maintains that: @@ -3907,8 +3903,8 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( class LazyExtensionRangeEmitter { public: - LazyExtensionRangeEmitter(MessageGenerator* mg, io::Printer* printer) - : mg_(mg), format_(printer) {} + LazyExtensionRangeEmitter(MessageGenerator* mg, io::Printer* p) + : mg_(mg), p_(p) {} void AddToRange(const Descriptor::ExtensionRange* range) { if (!has_current_range_) { @@ -3924,15 +3920,14 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( void Flush() { if (has_current_range_) { - mg_->GenerateSerializeOneExtensionRange(format_.printer(), - ¤t_combined_range_); + mg_->GenerateSerializeOneExtensionRange(p_, ¤t_combined_range_); } has_current_range_ = false; } private: MessageGenerator* mg_; - Formatter format_; + io::Printer* p_; bool has_current_range_ = false; Descriptor::ExtensionRange current_combined_range_; }; @@ -3982,8 +3977,8 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( // Merge the fields and the extension ranges, both sorted by field number. { - LazySerializerEmitter e(this, printer); - LazyExtensionRangeEmitter re(this, printer); + LazySerializerEmitter e(this, p); + LazyExtensionRangeEmitter re(this, p); LargestWeakFieldHolder largest_weak_field; int i, j; for (i = 0, j = 0; @@ -4013,9 +4008,6 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( e.EmitIfNotNull(largest_weak_field.Release()); } - std::map vars; - SetUnknownFieldsVariable(descriptor_, options_, &vars); - format.AddMap(vars); format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n"); format.Indent(); if (UseUnknownFieldSet(descriptor_->file(), options_)) { @@ -4034,8 +4026,8 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( } void MessageGenerator::GenerateSerializeWithCachedSizesBodyShuffled( - io::Printer* printer) { - Formatter format(printer, variables_); + io::Printer* p) { + Formatter format(p); std::vector ordered_fields = SortFieldsByNumber(descriptor_); @@ -4077,7 +4069,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBodyShuffled( format("case $1$: {\n", index++); format.Indent(); - GenerateSerializeOneField(printer, f, -1); + GenerateSerializeOneField(p, f, -1); format("break;\n"); format.Outdent(); @@ -4088,7 +4080,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBodyShuffled( format("case $1$: {\n", index++); format.Indent(); - GenerateSerializeOneExtensionRange(printer, r); + GenerateSerializeOneExtensionRange(p, r); format("break;\n"); format.Outdent(); @@ -4105,9 +4097,6 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBodyShuffled( format.Outdent(); format("}\n"); - std::map vars; - SetUnknownFieldsVariable(descriptor_, options_, &vars); - format.AddMap(vars); format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n"); format.Indent(); if (UseUnknownFieldSet(descriptor_->file(), options_)) { @@ -4141,15 +4130,12 @@ std::vector MessageGenerator::RequiredFieldsBitMask() const { return masks; } -void MessageGenerator::GenerateByteSize(io::Printer* printer) { +void MessageGenerator::GenerateByteSize(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; - Formatter format(printer, variables_); + Formatter format(p); if (descriptor_->options().message_set_wire_format()) { // Special-case MessageSet. - std::map vars; - SetUnknownFieldsVariable(descriptor_, options_, &vars); - format.AddMap(vars); format( "size_t $classname$::ByteSizeLong() const {\n" "$annotate_bytesize$" @@ -4184,7 +4170,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { FieldName(field)); format.Indent(); PrintFieldComment(format, field); - field_generators_.get(field).GenerateByteSize(printer); + field_generators_.get(field).GenerateByteSize(p); format.Outdent(); format("}\n"); } @@ -4211,10 +4197,6 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { "\n"); } - std::map vars; - SetUnknownFieldsVariable(descriptor_, options_, &vars); - format.AddMap(vars); - // Handle required fields (if any). We expect all of them to be // present, so emit one conditional that checks for that. If they are all // present then the fast path executes; otherwise the slow path executes. @@ -4229,7 +4211,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { for (auto field : optimized_order_) { if (!field->is_required()) continue; PrintFieldComment(format, field); - field_generators_.get(field).GenerateByteSize(printer); + field_generators_.get(field).GenerateByteSize(p); format("\n"); } format.Outdent(); @@ -4244,7 +4226,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { PrintFieldComment(format, field); format("if (_internal_has_$1$()) {\n", FieldName(field)); format.Indent(); - field_generators_.get(field).GenerateByteSize(printer); + field_generators_.get(field).GenerateByteSize(p); format.Outdent(); format("}\n"); } @@ -4274,7 +4256,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { const std::vector& chunk = chunks[chunk_index]; const bool have_outer_if = chunk.size() > 1 && HasWordIndex(chunk[0]) != kNoHasbit; - cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "", printer); + cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "", p); if (have_outer_if) { // Emit an if() that will let us skip the whole chunk if none are set. @@ -4309,17 +4291,15 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { // No presence check is required. need_extra_newline = true; } else if (HasHasbit(field)) { - PrintPresenceCheck(format, field, has_bit_indices_, printer, - &cached_has_word_index); + PrintPresenceCheck(field, has_bit_indices_, p, &cached_has_word_index); have_enclosing_if = true; } else { // Without field presence: field is serialized only if it has a // non-default value. - have_enclosing_if = - EmitFieldNonDefaultCondition(printer, "this->", field); + have_enclosing_if = EmitFieldNonDefaultCondition(p, "this->", field); } - generator.GenerateByteSize(printer); + generator.GenerateByteSize(p); if (have_enclosing_if) { format.Outdent(); @@ -4337,7 +4317,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { format("}\n"); } - if (cold_skipper.OnEndChunk(chunk_index, printer)) { + if (cold_skipper.OnEndChunk(chunk_index, p)) { // Reset here as it may have been updated in just closed if statement. cached_has_word_index = -1; } @@ -4353,7 +4333,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); format.Indent(); if (!IsFieldStripped(field, options_)) { - field_generators_.get(field).GenerateByteSize(printer); + field_generators_.get(field).GenerateByteSize(p); } format("break;\n"); format.Outdent(); @@ -4402,9 +4382,9 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { format("}\n"); } -void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { +void MessageGenerator::GenerateIsInitialized(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; - Formatter format(printer, variables_); + Formatter format(p); format("bool $classname$::IsInitialized() const {\n"); format.Indent(); @@ -4423,7 +4403,7 @@ void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { // Now check that all non-oneof embedded messages are initialized. for (auto field : optimized_order_) { - field_generators_.get(field).GenerateIsInitialized(printer); + field_generators_.get(field).GenerateIsInitialized(p); } if (num_weak_fields_) { // For Weak fields. @@ -4452,7 +4432,7 @@ void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); format.Indent(); if (!IsFieldStripped(field, options_)) { - field_generators_.get(field).GenerateIsInitialized(printer); + field_generators_.get(field).GenerateIsInitialized(p); } format("break;\n"); format.Outdent(); diff --git a/src/google/protobuf/compiler/cpp/message.h b/src/google/protobuf/compiler/cpp/message.h index 3b087d3fda..019660692a 100644 --- a/src/google/protobuf/compiler/cpp/message.h +++ b/src/google/protobuf/compiler/cpp/message.h @@ -37,42 +37,38 @@ #include #include +#include #include #include #include +#include +#include +#include "absl/container/flat_hash_map.h" +#include "google/protobuf/compiler/cpp/enum.h" +#include "google/protobuf/compiler/cpp/extension.h" #include "google/protobuf/compiler/cpp/field.h" #include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/cpp/message_layout_helper.h" #include "google/protobuf/compiler/cpp/options.h" #include "google/protobuf/compiler/cpp/parse_function_generator.h" - -namespace google { -namespace protobuf { -namespace io { -class Printer; // printer.h -} -} // namespace protobuf -} // namespace google +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { namespace compiler { namespace cpp { - -class EnumGenerator; // enum.h -class ExtensionGenerator; // extension.h - class MessageGenerator { public: - // See generator.cc for the meaning of dllexport_decl. MessageGenerator(const Descriptor* descriptor, - const std::map& vars, + const std::map& ignored, int index_in_file_messages, const Options& options, MessageSCCAnalyzer* scc_analyzer); + MessageGenerator(const MessageGenerator&) = delete; MessageGenerator& operator=(const MessageGenerator&) = delete; - ~MessageGenerator(); + + ~MessageGenerator() = default; // Append the two types of nested generators to the corresponding vector. void AddGenerators( @@ -80,94 +76,94 @@ class MessageGenerator { std::vector>* extension_generators); // Generate definitions for this class and all its nested types. - void GenerateClassDefinition(io::Printer* printer); + void GenerateClassDefinition(io::Printer* p); // Generate definitions of inline methods (placed at the end of the header // file). - void GenerateInlineMethods(io::Printer* printer); - - // Source file stuff. + void GenerateInlineMethods(io::Printer* p); // Generate all non-inline methods for this class. - void GenerateClassMethods(io::Printer* printer); + void GenerateClassMethods(io::Printer* p); // Generate source file code that should go outside any namespace. - void GenerateSourceInProto2Namespace(io::Printer* printer); + void GenerateSourceInProto2Namespace(io::Printer* p); - private: - // Generate declarations and definitions of accessors for fields. - void GenerateFieldAccessorDeclarations(io::Printer* printer); - void GenerateFieldAccessorDefinitions(io::Printer* printer); + + void GenerateInitDefaultSplitInstance(io::Printer* p); + + // Generate the constexpr constructor for constant initialization of the + // default instance. + void GenerateConstexprConstructor(io::Printer* p); + + void GenerateSchema(io::Printer* p, int offset, int has_offset); // Generate the field offsets array. Returns the a pair of the total number // of entries generated and the index of the first has_bit entry. - std::pair GenerateOffsets(io::Printer* printer); - void GenerateSchema(io::Printer* printer, int offset, int has_offset); + std::pair GenerateOffsets(io::Printer* p); + + const Descriptor* descriptor() const { return descriptor_; } + + private: + // Generate declarations and definitions of accessors for fields. + void GenerateFieldAccessorDeclarations(io::Printer* p); + void GenerateFieldAccessorDefinitions(io::Printer* p); // Generate constructors and destructor. - void GenerateStructors(io::Printer* printer); + void GenerateStructors(io::Printer* p); // The compiler typically generates multiple copies of each constructor and // destructor: http://gcc.gnu.org/bugs.html#nonbugs_cxx // Placing common code in a separate method reduces the generated code size. // // Generate the shared constructor code. - void GenerateSharedConstructorCode(io::Printer* printer); + void GenerateSharedConstructorCode(io::Printer* p); // Generate the shared destructor code. - void GenerateSharedDestructorCode(io::Printer* printer); + void GenerateSharedDestructorCode(io::Printer* p); // Generate the arena-specific destructor code. - void GenerateArenaDestructorCode(io::Printer* printer); - - // Generate the constexpr constructor for constant initialization of the - // default instance. - void GenerateConstexprConstructor(io::Printer* printer); - - void GenerateInitDefaultSplitInstance(io::Printer* printer); + void GenerateArenaDestructorCode(io::Printer* p); // Generate standard Message methods. - void GenerateClear(io::Printer* printer); - void GenerateOneofClear(io::Printer* printer); - void GenerateVerify(io::Printer* printer); - void GenerateSerializeWithCachedSizes(io::Printer* printer); - void GenerateSerializeWithCachedSizesToArray(io::Printer* printer); - void GenerateSerializeWithCachedSizesBody(io::Printer* printer); - void GenerateSerializeWithCachedSizesBodyShuffled(io::Printer* printer); - void GenerateByteSize(io::Printer* printer); - void GenerateMergeFrom(io::Printer* printer); - void GenerateClassSpecificMergeImpl(io::Printer* printer); - void GenerateCopyFrom(io::Printer* printer); - void GenerateSwap(io::Printer* printer); - void GenerateIsInitialized(io::Printer* printer); + void GenerateClear(io::Printer* p); + void GenerateOneofClear(io::Printer* p); + void GenerateVerify(io::Printer* p); + void GenerateSerializeWithCachedSizes(io::Printer* p); + void GenerateSerializeWithCachedSizesToArray(io::Printer* p); + void GenerateSerializeWithCachedSizesBody(io::Printer* p); + void GenerateSerializeWithCachedSizesBodyShuffled(io::Printer* p); + void GenerateByteSize(io::Printer* p); + void GenerateMergeFrom(io::Printer* p); + void GenerateClassSpecificMergeImpl(io::Printer* p); + void GenerateCopyFrom(io::Printer* p); + void GenerateSwap(io::Printer* p); + void GenerateIsInitialized(io::Printer* p); // Helpers for GenerateSerializeWithCachedSizes(). // // cached_has_bit_index maintains that: // cached_has_bits = _has_bits_[cached_has_bit_index] // for cached_has_bit_index >= 0 - void GenerateSerializeOneField(io::Printer* printer, - const FieldDescriptor* field, + void GenerateSerializeOneField(io::Printer* p, const FieldDescriptor* field, int cached_has_bits_index); // Generate a switch statement to serialize 2+ fields from the same oneof. // Or, if fields.size() == 1, just call GenerateSerializeOneField(). void GenerateSerializeOneofFields( - io::Printer* printer, const std::vector& fields); + io::Printer* p, const std::vector& fields); void GenerateSerializeOneExtensionRange( - io::Printer* printer, const Descriptor::ExtensionRange* range); + io::Printer* p, const Descriptor::ExtensionRange* range); // Generates has_foo() functions and variables for singular field has-bits. void GenerateSingularFieldHasBits(const FieldDescriptor* field, - Formatter format); + io::Printer* p); // Generates has_foo() functions and variables for oneof field has-bits. - void GenerateOneofHasBits(io::Printer* printer); + void GenerateOneofHasBits(io::Printer* p); // Generates has_foo_bar() functions for oneof members. - void GenerateOneofMemberHasBits(const FieldDescriptor* field, - const Formatter& format); + void GenerateOneofMemberHasBits(const FieldDescriptor* field, io::Printer* p); // Generates the clear_foo() method for a field. void GenerateFieldClear(const FieldDescriptor* field, bool is_inline, - Formatter format); + io::Printer* p); // Generates the body of the message's copy constructor. - void GenerateCopyConstructorBody(io::Printer* printer) const; + void GenerateCopyConstructorBody(io::Printer* p) const; // Returns the level that this message needs ArenaDtor. If the message has // a field that is not arena-exclusive, it needs an ArenaDtor @@ -183,15 +179,13 @@ class MessageGenerator { size_t HasBitsSize() const; size_t InlinedStringDonatedSize() const; - int HasBitIndex(const FieldDescriptor* a) const; - int HasByteIndex(const FieldDescriptor* a) const; - int HasWordIndex(const FieldDescriptor* a) const; - bool SameHasByte(const FieldDescriptor* a, const FieldDescriptor* b) const; + int HasBitIndex(const FieldDescriptor* field) const; + int HasByteIndex(const FieldDescriptor* field) const; + int HasWordIndex(const FieldDescriptor* field) const; std::vector RequiredFieldsBitMask() const; const Descriptor* descriptor_; int index_in_file_messages_; - std::string classname_; Options options_; FieldGeneratorMap field_generators_; // optimized_order_ is the order we layout the message's fields in the @@ -201,19 +195,19 @@ class MessageGenerator { // optimized_order_ excludes oneof fields and weak fields. std::vector optimized_order_; std::vector has_bit_indices_; - int max_has_bit_index_; + int max_has_bit_index_ = 0; // A map from field index to inlined_string index. For non-inlined-string // fields, the element is -1. If there is no inlined string in the message, // this is empty. std::vector inlined_string_indices_; // The count of inlined_string fields in the message. - int max_inlined_string_index_; + int max_inlined_string_index_ = 0; std::vector enum_generators_; std::vector extension_generators_; - int num_required_fields_; - int num_weak_fields_; + int num_required_fields_ = 0; + int num_weak_fields_ = 0; std::unique_ptr message_layout_helper_; std::unique_ptr parse_function_generator_; @@ -222,7 +216,6 @@ class MessageGenerator { std::map variables_; - friend class FileGenerator; }; } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/message_field.cc b/src/google/protobuf/compiler/cpp/message_field.cc index 74cca18955..d2df9a2592 100644 --- a/src/google/protobuf/compiler/cpp/message_field.cc +++ b/src/google/protobuf/compiler/cpp/message_field.cc @@ -191,12 +191,19 @@ void MessageFieldGenerator::GenerateInlineAccessorDefinitions( } else { format(" $field$ = $name$;\n"); } + auto nonempty = [this](const char* fn) { + auto var_it = variables_.find(fn); + return var_it != variables_.end() && !var_it->second.empty(); + }; + if (nonempty("set_hasbit") || nonempty("clear_hasbit")) { + format( + " if ($name$) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n"); + } format( - " if ($name$) {\n" - " $set_hasbit$\n" - " } else {\n" - " $clear_hasbit$\n" - " }\n" "$annotate_set$" " // @@protoc_insertion_point(field_unsafe_arena_set_allocated" ":$full_name$)\n" diff --git a/src/google/protobuf/compiler/cpp/parse_function_generator.cc b/src/google/protobuf/compiler/cpp/parse_function_generator.cc index 00f48236d9..70ff98f40f 100644 --- a/src/google/protobuf/compiler/cpp/parse_function_generator.cc +++ b/src/google/protobuf/compiler/cpp/parse_function_generator.cc @@ -585,6 +585,11 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) { QualifiedClassName(aux_entry.field->message_type(), options_)); break; + case TailCallTableInfo::kSubMessageWeak: + format("{::_pbi::FieldAuxDefaultMessage{}, &$1$},\n", + QualifiedDefaultInstancePtr( + aux_entry.field->message_type(), options_)); + break; case TailCallTableInfo::kEnumRange: format("{$1$, $2$},\n", aux_entry.enum_range.start, aux_entry.enum_range.size); @@ -628,24 +633,26 @@ void ParseFunctionGenerator::GenerateFastFieldEntries(Formatter& format) { GOOGLE_CHECK(!ShouldSplit(info.field, options_)); std::string func_name = info.func_name; - // For 1-byte tags we have a more optimized version of the varint parser - // that can hardcode the offset and has bit. - if (absl::EndsWith(func_name, "V8S1") || - absl::EndsWith(func_name, "V32S1") || - absl::EndsWith(func_name, "V64S1")) { - std::string field_type = absl::EndsWith(func_name, "V8S1") ? "bool" - : absl::EndsWith(func_name, "V32S1") - ? "uint32_t" - : "uint64_t"; - func_name = - absl::StrCat("::_pbi::TcParser::SingularVarintNoZag1<", field_type, - ", offsetof(", // - ClassName(info.field->containing_type()), // - ", ", // - FieldMemberName(info.field, /*split=*/false), // - "), ", // - info.hasbit_idx, // - ">()"); + if (GetOptimizeFor(info.field->file(), options_) == FileOptions::SPEED) { + // For 1-byte tags we have a more optimized version of the varint parser + // that can hardcode the offset and has bit. + if (absl::EndsWith(func_name, "V8S1") || + absl::EndsWith(func_name, "V32S1") || + absl::EndsWith(func_name, "V64S1")) { + std::string field_type = absl::EndsWith(func_name, "V8S1") ? "bool" + : absl::EndsWith(func_name, "V32S1") + ? "uint32_t" + : "uint64_t"; + func_name = absl::StrCat( + "::_pbi::TcParser::SingularVarintNoZag1<", field_type, + ", offsetof(", // + ClassName(info.field->containing_type()), // + ", ", // + FieldMemberName(info.field, /*split=*/false), // + "), ", // + info.hasbit_idx, // + ">()"); + } } format( @@ -708,20 +715,19 @@ static void FormatFieldKind(Formatter& format, case fl::kFkMessage: { format(" | ::_fl::kMessage"); - static constexpr const char* kRepNames[] = {nullptr, "Group", "Lazy", - "IWeak"}; + static constexpr const char* kRepNames[] = {nullptr, "Group", "Lazy"}; static_assert((fl::kRepGroup >> fl::kRepShift) == 1, ""); static_assert((fl::kRepLazy >> fl::kRepShift) == 2, ""); - static_assert((fl::kRepIWeak >> fl::kRepShift) == 3, ""); if (auto* rep = kRepNames[rep_index]) { format(" | ::_fl::kRep$1$", rep); } - static constexpr const char* kXFormNames[] = {nullptr, "Default", - "Table"}; + static constexpr const char* kXFormNames[] = {nullptr, "Default", "Table", + "WeakPtr"}; static_assert((fl::kTvDefault >> fl::kTvShift) == 1, ""); static_assert((fl::kTvTable >> fl::kTvShift) == 2, ""); + static_assert((fl::kTvWeakPtr >> fl::kTvShift) == 3, ""); if (auto* xform = kXFormNames[tv_index]) { format(" | ::_fl::kTv$1$", xform); diff --git a/src/google/protobuf/compiler/cpp/primitive_field.cc b/src/google/protobuf/compiler/cpp/primitive_field.cc index bad879536b..ff30c94efb 100644 --- a/src/google/protobuf/compiler/cpp/primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/primitive_field.cc @@ -36,7 +36,6 @@ #include "google/protobuf/io/printer.h" #include "google/protobuf/wire_format.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/str_cat.h" #include "google/protobuf/compiler/cpp/helpers.h" diff --git a/src/google/protobuf/compiler/cpp/string_field.cc b/src/google/protobuf/compiler/cpp/string_field.cc index 3b05c36f5c..bcb125389c 100644 --- a/src/google/protobuf/compiler/cpp/string_field.cc +++ b/src/google/protobuf/compiler/cpp/string_field.cc @@ -35,11 +35,11 @@ #include "google/protobuf/compiler/cpp/string_field.h" #include "google/protobuf/io/printer.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/str_cat.h" #include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/descriptor.pb.h" +#include "google/protobuf/stubs/strutil.h" namespace google { namespace protobuf { @@ -313,12 +313,20 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions( format( "}\n" "inline void $classname$::set_allocated_$name$(std::string* $name$) {\n" - "$maybe_prepare_split_message$" - " if ($name$ != nullptr) {\n" - " $set_hasbit$\n" - " } else {\n" - " $clear_hasbit$\n" - " }\n"); + "$maybe_prepare_split_message$"); + + auto nonempty = [this](const char* fn) { + auto var_it = variables_.find(fn); + return var_it != variables_.end() && !var_it->second.empty(); + }; + if (nonempty("set_hasbit") || nonempty("clear_hasbit")) { + format( + " if ($name$ != nullptr) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n"); + } if (!inlined_) { format(" $field$.SetAllocated($name$, GetArenaForAllocation());\n"); if (descriptor_->default_value_string().empty()) { diff --git a/src/google/protobuf/compiler/cpp/unittest.inc b/src/google/protobuf/compiler/cpp/unittest.inc index 2d65eaddf6..f1c498638f 100644 --- a/src/google/protobuf/compiler/cpp/unittest.inc +++ b/src/google/protobuf/compiler/cpp/unittest.inc @@ -50,6 +50,7 @@ #include #include "google/protobuf/compiler/cpp/unittest.h" +#include "absl/strings/cord.h" #include "absl/strings/string_view.h" #ifndef _MSC_VER // We exclude this large proto because it's too large for diff --git a/src/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc b/src/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc index 315f595446..798cab5c47 100644 --- a/src/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc +++ b/src/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc @@ -41,7 +41,6 @@ #include "google/protobuf/testing/file.h" #include "google/protobuf/testing/googletest.h" -#include "google/protobuf/stubs/strutil.h" #include #include "absl/strings/ascii.h" #include "absl/strings/escaping.h" diff --git a/src/google/protobuf/compiler/csharp/csharp_map_field.cc b/src/google/protobuf/compiler/csharp/csharp_map_field.cc index 50d8b1d828..efe87f2a6a 100644 --- a/src/google/protobuf/compiler/csharp/csharp_map_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_map_field.cc @@ -88,7 +88,7 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) { void MapFieldGenerator::GenerateMergingCode(io::Printer* printer) { printer->Print( variables_, - "$name$_.MergeFrom(other.$name$_);\n"); + "$name$_.Add(other.$name$_);\n"); } void MapFieldGenerator::GenerateParsingCode(io::Printer* printer) { diff --git a/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc index e23c48a24e..c6d6cd08e6 100644 --- a/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc +++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc @@ -38,8 +38,8 @@ #include "google/protobuf/compiler/csharp/csharp_field_base.h" #include "google/protobuf/compiler/csharp/csharp_helpers.h" #include "google/protobuf/compiler/csharp/csharp_message.h" -#include "google/protobuf/compiler/csharp/names.h" #include "google/protobuf/compiler/csharp/csharp_options.h" +#include "google/protobuf/compiler/csharp/names.h" #include "google/protobuf/descriptor.h" #include "google/protobuf/descriptor.pb.h" #include "google/protobuf/io/printer.h" diff --git a/src/google/protobuf/compiler/importer.h b/src/google/protobuf/compiler/importer.h index bab4b73d14..3b8dd51d58 100644 --- a/src/google/protobuf/compiler/importer.h +++ b/src/google/protobuf/compiler/importer.h @@ -221,12 +221,6 @@ class PROTOBUF_EXPORT SourceTree { SourceTree& operator=(const SourceTree&) = delete; virtual ~SourceTree(); - // This is a temporary typedef alias to allow migrating the argument type of - // Open in an atomic change without touching certain directories which are - // restricted for various reasons. This must match the argument type used - // below. - using SourceTreeOpenArgumentType = absl::string_view; - // Open the given file and return a stream that reads it, or NULL if not // found. The caller takes ownership of the returned object. The filename // must be a path relative to the root of the source tree and must not diff --git a/src/google/protobuf/compiler/java/context.cc b/src/google/protobuf/compiler/java/context.cc index e750dcbc86..b9f0c8f15a 100644 --- a/src/google/protobuf/compiler/java/context.cc +++ b/src/google/protobuf/compiler/java/context.cc @@ -31,7 +31,6 @@ #include "google/protobuf/compiler/java/context.h" #include "google/protobuf/descriptor.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/str_cat.h" #include "google/protobuf/compiler/java/field.h" #include "google/protobuf/compiler/java/helpers.h" diff --git a/src/google/protobuf/compiler/java/doc_comment.cc b/src/google/protobuf/compiler/java/doc_comment.cc index a515eb20ce..fb5b5543f3 100644 --- a/src/google/protobuf/compiler/java/doc_comment.cc +++ b/src/google/protobuf/compiler/java/doc_comment.cc @@ -38,7 +38,6 @@ #include "google/protobuf/io/printer.h" #include "google/protobuf/descriptor.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/str_split.h" #include "google/protobuf/descriptor.pb.h" #include "google/protobuf/io/printer.h" diff --git a/src/google/protobuf/compiler/java/enum.cc b/src/google/protobuf/compiler/java/enum.cc index f3e1b4243e..788c9dd60f 100644 --- a/src/google/protobuf/compiler/java/enum.cc +++ b/src/google/protobuf/compiler/java/enum.cc @@ -38,7 +38,6 @@ #include #include "google/protobuf/io/printer.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/str_cat.h" #include "google/protobuf/compiler/java/context.h" #include "google/protobuf/compiler/java/doc_comment.h" diff --git a/src/google/protobuf/compiler/java/enum_field.cc b/src/google/protobuf/compiler/java/enum_field.cc index 2f0828fdd7..b6c8dc796c 100644 --- a/src/google/protobuf/compiler/java/enum_field.cc +++ b/src/google/protobuf/compiler/java/enum_field.cc @@ -674,6 +674,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateMembers( io::Printer* printer) const { printer->Print( variables_, + "@SuppressWarnings(\"serial\")\n" "private java.util.List $name$_;\n" "private static final " "com.google.protobuf.Internal.ListAdapter.Converter<\n" @@ -986,7 +987,6 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderParsingCodeFromPacked( "}\n" "input.popLimit(oldLimit);\n"); } - void RepeatedImmutableEnumFieldGenerator::GenerateSerializationCode( io::Printer* printer) const { if (descriptor_->is_packed()) { diff --git a/src/google/protobuf/compiler/java/enum_field_lite.cc b/src/google/protobuf/compiler/java/enum_field_lite.cc index d3a7fb0ce2..470bc9d2fd 100644 --- a/src/google/protobuf/compiler/java/enum_field_lite.cc +++ b/src/google/protobuf/compiler/java/enum_field_lite.cc @@ -42,7 +42,6 @@ #include "google/protobuf/stubs/common.h" #include "google/protobuf/io/printer.h" #include "google/protobuf/wire_format.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/str_cat.h" #include "google/protobuf/compiler/java/context.h" #include "google/protobuf/compiler/java/doc_comment.h" diff --git a/src/google/protobuf/compiler/java/enum_lite.cc b/src/google/protobuf/compiler/java/enum_lite.cc index a04f814972..47cae62bc2 100644 --- a/src/google/protobuf/compiler/java/enum_lite.cc +++ b/src/google/protobuf/compiler/java/enum_lite.cc @@ -38,7 +38,6 @@ #include #include "google/protobuf/io/printer.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/str_cat.h" #include "google/protobuf/compiler/java/context.h" #include "google/protobuf/compiler/java/doc_comment.h" diff --git a/src/google/protobuf/compiler/java/extension.cc b/src/google/protobuf/compiler/java/extension.cc index 0e42a01777..24a392edd8 100644 --- a/src/google/protobuf/compiler/java/extension.cc +++ b/src/google/protobuf/compiler/java/extension.cc @@ -35,7 +35,6 @@ #include "google/protobuf/compiler/java/extension.h" #include "google/protobuf/io/printer.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/str_cat.h" #include "google/protobuf/compiler/java/context.h" #include "google/protobuf/compiler/java/doc_comment.h" diff --git a/src/google/protobuf/compiler/java/extension_lite.cc b/src/google/protobuf/compiler/java/extension_lite.cc index 4c3b83a230..e18dc6536a 100644 --- a/src/google/protobuf/compiler/java/extension_lite.cc +++ b/src/google/protobuf/compiler/java/extension_lite.cc @@ -31,7 +31,6 @@ #include "google/protobuf/compiler/java/extension_lite.h" #include "google/protobuf/io/printer.h" -#include "google/protobuf/stubs/strutil.h" #include "google/protobuf/compiler/java/context.h" #include "google/protobuf/compiler/java/doc_comment.h" #include "google/protobuf/compiler/java/helpers.h" diff --git a/src/google/protobuf/compiler/java/field.cc b/src/google/protobuf/compiler/java/field.cc index 13aed84bd8..831f88ab2d 100644 --- a/src/google/protobuf/compiler/java/field.cc +++ b/src/google/protobuf/compiler/java/field.cc @@ -39,7 +39,6 @@ #include "google/protobuf/stubs/logging.h" #include "google/protobuf/stubs/common.h" #include "google/protobuf/io/printer.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/str_cat.h" #include "absl/strings/substitute.h" #include "google/protobuf/compiler/java/context.h" diff --git a/src/google/protobuf/compiler/java/file.cc b/src/google/protobuf/compiler/java/file.cc index 20949d0ec8..4776277db2 100644 --- a/src/google/protobuf/compiler/java/file.cc +++ b/src/google/protobuf/compiler/java/file.cc @@ -41,7 +41,6 @@ #include "google/protobuf/io/printer.h" #include "google/protobuf/io/zero_copy_stream.h" #include "google/protobuf/dynamic_message.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/str_cat.h" #include "google/protobuf/compiler/java/context.h" #include "google/protobuf/compiler/java/enum.h" diff --git a/src/google/protobuf/compiler/java/map_field.cc b/src/google/protobuf/compiler/java/map_field.cc index 2f162af71c..2b69bb6e29 100644 --- a/src/google/protobuf/compiler/java/map_field.cc +++ b/src/google/protobuf/compiler/java/map_field.cc @@ -328,6 +328,7 @@ void ImmutableMapFieldGenerator::GenerateMembers(io::Printer* printer) const { " $value_default_value$);\n" "}\n"); printer->Print(variables_, + "@SuppressWarnings(\"serial\")\n" "private com.google.protobuf.MapField<\n" " $type_parameters$> $name$_;\n" "private com.google.protobuf.MapField<$type_parameters$>\n" @@ -847,7 +848,6 @@ void ImmutableMapFieldGenerator::GenerateBuilderParsingCode( " $name$__.getKey(), $name$__.getValue());\n"); } } - void ImmutableMapFieldGenerator::GenerateSerializationCode( io::Printer* printer) const { printer->Print(variables_, diff --git a/src/google/protobuf/compiler/java/message.cc b/src/google/protobuf/compiler/java/message.cc index 508e41f883..eae7bb3bcc 100644 --- a/src/google/protobuf/compiler/java/message.cc +++ b/src/google/protobuf/compiler/java/message.cc @@ -44,7 +44,6 @@ #include "google/protobuf/io/printer.h" #include "google/protobuf/descriptor.h" #include "google/protobuf/wire_format.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/ascii.h" #include "absl/strings/str_cat.h" #include "absl/strings/substitute.h" @@ -438,6 +437,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { // oneofCase_ and oneof_ printer->Print(vars, "private int $oneof_name$Case_ = 0;\n" + "@SuppressWarnings(\"serial\")\n" "private java.lang.Object $oneof_name$_;\n"); // OneofCase enum printer->Print( @@ -1587,6 +1587,7 @@ void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) { " defaultInstance.getDescriptorForType().getFullName());\n" "}\n" "\n" + "@SuppressWarnings(\"serial\")\n" "private volatile com.google.protobuf.Message cachedUnpackValue;\n" "\n" "@java.lang.SuppressWarnings(\"unchecked\")\n" diff --git a/src/google/protobuf/compiler/java/message_builder.cc b/src/google/protobuf/compiler/java/message_builder.cc index 076b0429c1..150c4e6c4c 100644 --- a/src/google/protobuf/compiler/java/message_builder.cc +++ b/src/google/protobuf/compiler/java/message_builder.cc @@ -42,7 +42,6 @@ #include "google/protobuf/io/coded_stream.h" #include "google/protobuf/io/printer.h" #include "google/protobuf/wire_format.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/ascii.h" #include "absl/strings/str_cat.h" #include "absl/strings/substitute.h" diff --git a/src/google/protobuf/compiler/java/message_builder_lite.cc b/src/google/protobuf/compiler/java/message_builder_lite.cc index adff67eb33..1f9d13e9b6 100644 --- a/src/google/protobuf/compiler/java/message_builder_lite.cc +++ b/src/google/protobuf/compiler/java/message_builder_lite.cc @@ -43,7 +43,6 @@ #include "google/protobuf/io/coded_stream.h" #include "google/protobuf/io/printer.h" #include "google/protobuf/wire_format.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/str_cat.h" #include "absl/strings/substitute.h" #include "google/protobuf/compiler/java/context.h" diff --git a/src/google/protobuf/compiler/java/message_field.cc b/src/google/protobuf/compiler/java/message_field.cc index 42905c34a0..0e06ed77d8 100644 --- a/src/google/protobuf/compiler/java/message_field.cc +++ b/src/google/protobuf/compiler/java/message_field.cc @@ -39,7 +39,6 @@ #include "google/protobuf/io/printer.h" #include "google/protobuf/wire_format.h" -#include "google/protobuf/stubs/strutil.h" #include "google/protobuf/compiler/java/context.h" #include "google/protobuf/compiler/java/doc_comment.h" #include "google/protobuf/compiler/java/helpers.h" @@ -887,7 +886,8 @@ void RepeatedImmutableMessageFieldGenerator::GenerateInterfaceMembers( void RepeatedImmutableMessageFieldGenerator::GenerateMembers( io::Printer* printer) const { - printer->Print(variables_, "private java.util.List<$type$> $name$_;\n"); + printer->Print(variables_, "@SuppressWarnings(\"serial\")\n" + "private java.util.List<$type$> $name$_;\n"); PrintExtraFieldInfo(variables_, printer); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, diff --git a/src/google/protobuf/compiler/java/message_field_lite.cc b/src/google/protobuf/compiler/java/message_field_lite.cc index bc7c99f5e1..d01ccc102d 100644 --- a/src/google/protobuf/compiler/java/message_field_lite.cc +++ b/src/google/protobuf/compiler/java/message_field_lite.cc @@ -40,7 +40,6 @@ #include "google/protobuf/io/printer.h" #include "google/protobuf/wire_format.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/str_cat.h" #include "google/protobuf/compiler/java/context.h" #include "google/protobuf/compiler/java/doc_comment.h" diff --git a/src/google/protobuf/compiler/java/message_lite.cc b/src/google/protobuf/compiler/java/message_lite.cc index b087728f27..475a30b9f5 100644 --- a/src/google/protobuf/compiler/java/message_lite.cc +++ b/src/google/protobuf/compiler/java/message_lite.cc @@ -44,7 +44,6 @@ #include "google/protobuf/io/coded_stream.h" #include "google/protobuf/io/printer.h" #include "google/protobuf/wire_format.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/ascii.h" #include "absl/strings/str_cat.h" #include "absl/strings/substitute.h" diff --git a/src/google/protobuf/compiler/java/primitive_field.cc b/src/google/protobuf/compiler/java/primitive_field.cc index cc9255c831..87dbdb6a50 100644 --- a/src/google/protobuf/compiler/java/primitive_field.cc +++ b/src/google/protobuf/compiler/java/primitive_field.cc @@ -42,7 +42,6 @@ #include "google/protobuf/stubs/common.h" #include "google/protobuf/io/printer.h" #include "google/protobuf/wire_format.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/str_cat.h" #include "google/protobuf/compiler/java/context.h" #include "google/protobuf/compiler/java/doc_comment.h" @@ -709,7 +708,8 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateInterfaceMembers( void RepeatedImmutablePrimitiveFieldGenerator::GenerateMembers( io::Printer* printer) const { - printer->Print(variables_, "private $field_list_type$ $name$_;\n"); + printer->Print(variables_, "@SuppressWarnings(\"serial\")\n" + "private $field_list_type$ $name$_;\n"); PrintExtraFieldInfo(variables_, printer); WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); printer->Print(variables_, diff --git a/src/google/protobuf/compiler/java/primitive_field_lite.cc b/src/google/protobuf/compiler/java/primitive_field_lite.cc index 6db3a8c657..e370815326 100644 --- a/src/google/protobuf/compiler/java/primitive_field_lite.cc +++ b/src/google/protobuf/compiler/java/primitive_field_lite.cc @@ -42,7 +42,6 @@ #include "google/protobuf/stubs/common.h" #include "google/protobuf/io/printer.h" #include "google/protobuf/wire_format.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/ascii.h" #include "absl/strings/str_cat.h" #include "google/protobuf/compiler/java/context.h" diff --git a/src/google/protobuf/compiler/java/service.cc b/src/google/protobuf/compiler/java/service.cc index ab1d52cd08..d0c525b8c4 100644 --- a/src/google/protobuf/compiler/java/service.cc +++ b/src/google/protobuf/compiler/java/service.cc @@ -35,7 +35,6 @@ #include "google/protobuf/compiler/java/service.h" #include "google/protobuf/io/printer.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/str_cat.h" #include "google/protobuf/compiler/java/context.h" #include "google/protobuf/compiler/java/doc_comment.h" diff --git a/src/google/protobuf/compiler/java/string_field.cc b/src/google/protobuf/compiler/java/string_field.cc index 4ad529ce2b..910ee8e0ee 100644 --- a/src/google/protobuf/compiler/java/string_field.cc +++ b/src/google/protobuf/compiler/java/string_field.cc @@ -43,7 +43,6 @@ #include "google/protobuf/stubs/common.h" #include "google/protobuf/io/printer.h" #include "google/protobuf/wire_format.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/str_cat.h" #include "google/protobuf/compiler/java/context.h" #include "google/protobuf/compiler/java/doc_comment.h" @@ -211,7 +210,8 @@ void ImmutableStringFieldGenerator::GenerateInterfaceMembers( void ImmutableStringFieldGenerator::GenerateMembers( io::Printer* printer) const { - printer->Print(variables_, "private volatile java.lang.Object $name$_;\n"); + printer->Print(variables_, "@SuppressWarnings(\"serial\")\n" + "private volatile java.lang.Object $name$_;\n"); PrintExtraFieldInfo(variables_, printer); if (HasHazzer(descriptor_)) { @@ -792,6 +792,7 @@ void RepeatedImmutableStringFieldGenerator::GenerateInterfaceMembers( void RepeatedImmutableStringFieldGenerator::GenerateMembers( io::Printer* printer) const { printer->Print(variables_, + "@SuppressWarnings(\"serial\")\n" "private com.google.protobuf.LazyStringList $name$_;\n"); PrintExtraFieldInfo(variables_, printer); WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); diff --git a/src/google/protobuf/compiler/java/string_field_lite.cc b/src/google/protobuf/compiler/java/string_field_lite.cc index 13fb9296e6..df86df7876 100644 --- a/src/google/protobuf/compiler/java/string_field_lite.cc +++ b/src/google/protobuf/compiler/java/string_field_lite.cc @@ -43,7 +43,6 @@ #include "google/protobuf/stubs/common.h" #include "google/protobuf/io/printer.h" #include "google/protobuf/wire_format.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/str_cat.h" #include "google/protobuf/compiler/java/context.h" #include "google/protobuf/compiler/java/doc_comment.h" diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc index ecaf76b981..dfce4fbe3c 100644 --- a/src/google/protobuf/compiler/main.cc +++ b/src/google/protobuf/compiler/main.cc @@ -28,12 +28,12 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include "google/protobuf/compiler/command_line_interface.h" #include "google/protobuf/compiler/cpp/generator.h" +#include "google/protobuf/compiler/csharp/csharp_generator.h" #include "google/protobuf/compiler/java/generator.h" #include "google/protobuf/compiler/java/kotlin_generator.h" -#include "google/protobuf/compiler/command_line_interface.h" -#include "google/protobuf/compiler/csharp/csharp_generator.h" -#include "google/protobuf/compiler/objectivec/objectivec_generator.h" +#include "google/protobuf/compiler/objectivec/generator.h" #include "google/protobuf/compiler/php/php_generator.h" #include "google/protobuf/compiler/python/generator.h" #include "google/protobuf/compiler/python/pyi_generator.h" diff --git a/src/google/protobuf/compiler/objectivec/BUILD.bazel b/src/google/protobuf/compiler/objectivec/BUILD.bazel index 248e2ab8cd..25fb412f24 100644 --- a/src/google/protobuf/compiler/objectivec/BUILD.bazel +++ b/src/google/protobuf/compiler/objectivec/BUILD.bazel @@ -21,7 +21,7 @@ cc_library( name = "names_internal", hdrs = [ "names.h", - "objectivec_nsobject_methods.h", + "nsobject_methods.h", ], srcs = [ "names.cc", @@ -29,6 +29,20 @@ cc_library( copts = COPTS, include_prefix = "google/protobuf/compiler/objectivec", visibility = ["//pkg:__pkg__"], + deps = [ + ":line_consumer", + "//src/google/protobuf/compiler:code_generator", + "//src/google/protobuf:protobuf_nowkt", + ], +) + +cc_library( + name = "line_consumer", + hdrs = ["line_consumer.h"], + srcs = ["line_consumer.cc"], + copts = COPTS, + include_prefix = "google/protobuf/compiler/objectivec", + visibility = ["//pkg:__pkg__"], deps = [ "//src/google/protobuf/compiler:code_generator", "//src/google/protobuf:protobuf_nowkt", @@ -38,32 +52,37 @@ cc_library( cc_library( name = "objectivec", srcs = [ - "objectivec_enum.cc", - "objectivec_enum_field.cc", - "objectivec_extension.cc", - "objectivec_field.cc", - "objectivec_file.cc", - "objectivec_generator.cc", - "objectivec_map_field.cc", - "objectivec_message.cc", - "objectivec_message_field.cc", - "objectivec_oneof.cc", - "objectivec_primitive_field.cc", + "enum.cc", + "enum_field.cc", + "extension.cc", + "field.cc", + "file.cc", + "generator.cc", + "helpers.cc", + "import_writer.cc", + "map_field.cc", + "message.cc", + "message_field.cc", + "oneof.cc", + "primitive_field.cc", + "text_format_decode_data.cc", ], hdrs = [ - "objectivec_enum.h", - "objectivec_enum_field.h", - "objectivec_extension.h", - "objectivec_field.h", - "objectivec_file.h", - "objectivec_generator.h", - "objectivec_helpers.h", - "objectivec_map_field.h", - "objectivec_message.h", - "objectivec_message_field.h", - "objectivec_oneof.h", - "objectivec_options.h", - "objectivec_primitive_field.h", + "enum.h", + "enum_field.h", + "extension.h", + "field.h", + "file.h", + "generator.h", + "helpers.h", + "import_writer.h", + "map_field.h", + "message.h", + "message_field.h", + "oneof.h", + "options.h", + "primitive_field.h", + "text_format_decode_data.h", ], copts = COPTS, include_prefix = "google/protobuf/compiler/objectivec", @@ -72,6 +91,7 @@ cc_library( "//src/google/protobuf/compiler:__pkg__", ], deps = [ + ":line_consumer", ":names", "//src/google/protobuf:protobuf_nowkt", "//src/google/protobuf/compiler:code_generator", @@ -80,16 +100,37 @@ cc_library( ) cc_test( - name = "helpers_unittest", - srcs = ["objectivec_helpers_unittest.cc"], + name = "line_consumer_unittest", + srcs = ["line_consumer_unittest.cc"], deps = [ - ":objectivec", + ":line_consumer", + "//src/google/protobuf/io", + "@com_google_googletest//:gtest", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "names_unittest", + srcs = ["names_unittest.cc"], + deps = [ + ":names", "//src/google/protobuf/io", "@com_google_googletest//:gtest", "@com_google_googletest//:gtest_main", ], ) +cc_test( + name = "text_format_decode_data_unittest", + srcs = ["text_format_decode_data_unittest.cc"], + deps = [ + ":objectivec", + "@com_google_googletest//:gtest", + "@com_google_googletest//:gtest_main", + ], +) + ################################################################################ # Distribution packaging ################################################################################ diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum.cc b/src/google/protobuf/compiler/objectivec/enum.cc similarity index 97% rename from src/google/protobuf/compiler/objectivec/objectivec_enum.cc rename to src/google/protobuf/compiler/objectivec/enum.cc index 13954ca563..fcd7706d17 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_enum.cc +++ b/src/google/protobuf/compiler/objectivec/enum.cc @@ -28,7 +28,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "google/protobuf/compiler/objectivec/objectivec_enum.h" +#include "google/protobuf/compiler/objectivec/enum.h" #include #include @@ -36,7 +36,9 @@ #include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" -#include "google/protobuf/compiler/objectivec/objectivec_helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/text_format_decode_data.h" #include "google/protobuf/io/printer.h" namespace google { diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum.h b/src/google/protobuf/compiler/objectivec/enum.h similarity index 100% rename from src/google/protobuf/compiler/objectivec/objectivec_enum.h rename to src/google/protobuf/compiler/objectivec/enum.h diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc b/src/google/protobuf/compiler/objectivec/enum_field.cc similarity index 97% rename from src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc rename to src/google/protobuf/compiler/objectivec/enum_field.cc index 049ff475d5..72d0b581f0 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc +++ b/src/google/protobuf/compiler/objectivec/enum_field.cc @@ -31,8 +31,9 @@ #include #include -#include "google/protobuf/compiler/objectivec/objectivec_enum_field.h" -#include "google/protobuf/compiler/objectivec/objectivec_helpers.h" +#include "google/protobuf/compiler/objectivec/enum_field.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/compiler/objectivec/helpers.h" #include "google/protobuf/io/printer.h" namespace google { diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h b/src/google/protobuf/compiler/objectivec/enum_field.h similarity index 97% rename from src/google/protobuf/compiler/objectivec/objectivec_enum_field.h rename to src/google/protobuf/compiler/objectivec/enum_field.h index 7bd3c32c75..1cbd6cffad 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h +++ b/src/google/protobuf/compiler/objectivec/enum_field.h @@ -33,7 +33,7 @@ #include #include -#include "google/protobuf/compiler/objectivec/objectivec_field.h" +#include "google/protobuf/compiler/objectivec/field.h" namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/objectivec/objectivec_extension.cc b/src/google/protobuf/compiler/objectivec/extension.cc similarity index 97% rename from src/google/protobuf/compiler/objectivec/objectivec_extension.cc rename to src/google/protobuf/compiler/objectivec/extension.cc index c97c9feade..f13bff0755 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_extension.cc +++ b/src/google/protobuf/compiler/objectivec/extension.cc @@ -28,12 +28,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "google/protobuf/compiler/objectivec/objectivec_extension.h" +#include "google/protobuf/compiler/objectivec/extension.h" #include #include "absl/strings/str_cat.h" -#include "google/protobuf/compiler/objectivec/objectivec_helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/compiler/objectivec/helpers.h" #include "google/protobuf/descriptor.pb.h" #include "google/protobuf/io/printer.h" diff --git a/src/google/protobuf/compiler/objectivec/objectivec_extension.h b/src/google/protobuf/compiler/objectivec/extension.h similarity index 100% rename from src/google/protobuf/compiler/objectivec/objectivec_extension.h rename to src/google/protobuf/compiler/objectivec/extension.h diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.cc b/src/google/protobuf/compiler/objectivec/field.cc similarity index 85% rename from src/google/protobuf/compiler/objectivec/objectivec_field.cc rename to src/google/protobuf/compiler/objectivec/field.cc index b98955b632..ca3c43a28f 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_field.cc +++ b/src/google/protobuf/compiler/objectivec/field.cc @@ -28,16 +28,17 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "google/protobuf/compiler/objectivec/objectivec_field.h" +#include "google/protobuf/compiler/objectivec/field.h" #include #include "absl/strings/str_cat.h" -#include "google/protobuf/compiler/objectivec/objectivec_enum_field.h" -#include "google/protobuf/compiler/objectivec/objectivec_helpers.h" -#include "google/protobuf/compiler/objectivec/objectivec_map_field.h" -#include "google/protobuf/compiler/objectivec/objectivec_message_field.h" -#include "google/protobuf/compiler/objectivec/objectivec_primitive_field.h" +#include "google/protobuf/compiler/objectivec/enum_field.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/map_field.h" +#include "google/protobuf/compiler/objectivec/message_field.h" +#include "google/protobuf/compiler/objectivec/primitive_field.h" #include "google/protobuf/io/printer.h" namespace google { @@ -116,6 +117,74 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["storage_attribute"] = ""; } +bool HasNonZeroDefaultValue(const FieldDescriptor* field) { + // Repeated fields don't have defaults. + if (field->is_repeated()) { + return false; + } + + // As much as checking field->has_default_value() seems useful, it isn't + // because of enums. proto2 syntax allows the first item in an enum (the + // default) to be non zero. So checking field->has_default_value() would + // result in missing this non zero default. See MessageWithOneBasedEnum in + // objectivec/Tests/unittest_objc.proto for a test Message to confirm this. + + // Some proto file set the default to the zero value, so make sure the value + // isn't the zero case. + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + return field->default_value_int32() != 0; + case FieldDescriptor::CPPTYPE_UINT32: + return field->default_value_uint32() != 0U; + case FieldDescriptor::CPPTYPE_INT64: + return field->default_value_int64() != 0LL; + case FieldDescriptor::CPPTYPE_UINT64: + return field->default_value_uint64() != 0ULL; + case FieldDescriptor::CPPTYPE_DOUBLE: + return field->default_value_double() != 0.0; + case FieldDescriptor::CPPTYPE_FLOAT: + return field->default_value_float() != 0.0f; + case FieldDescriptor::CPPTYPE_BOOL: + return field->default_value_bool(); + case FieldDescriptor::CPPTYPE_STRING: { + const std::string& default_string = field->default_value_string(); + return default_string.length() != 0; + } + case FieldDescriptor::CPPTYPE_ENUM: + return field->default_value_enum()->number() != 0; + case FieldDescriptor::CPPTYPE_MESSAGE: + return false; + } + + // Some compilers report reaching end of function even though all cases of + // the enum are handed in the switch. + GOOGLE_LOG(FATAL) << "Can't get here."; + return false; +} + +bool IsPrimitiveType(const FieldDescriptor* field) { + ObjectiveCType type = GetObjectiveCType(field); + switch (type) { + case OBJECTIVECTYPE_INT32: + case OBJECTIVECTYPE_UINT32: + case OBJECTIVECTYPE_INT64: + case OBJECTIVECTYPE_UINT64: + case OBJECTIVECTYPE_FLOAT: + case OBJECTIVECTYPE_DOUBLE: + case OBJECTIVECTYPE_BOOLEAN: + case OBJECTIVECTYPE_ENUM: + return true; + break; + default: + return false; + } +} + +bool IsReferenceType(const FieldDescriptor* field) { + return !IsPrimitiveType(field); +} + + } // namespace FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field) { diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.h b/src/google/protobuf/compiler/objectivec/field.h similarity index 100% rename from src/google/protobuf/compiler/objectivec/objectivec_field.h rename to src/google/protobuf/compiler/objectivec/field.h diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/file.cc similarity index 98% rename from src/google/protobuf/compiler/objectivec/objectivec_file.cc rename to src/google/protobuf/compiler/objectivec/file.cc index fc51baf866..ff74517963 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc +++ b/src/google/protobuf/compiler/objectivec/file.cc @@ -28,7 +28,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "google/protobuf/compiler/objectivec/objectivec_file.h" +#include "google/protobuf/compiler/objectivec/file.h" #include #include @@ -36,10 +36,12 @@ #include "google/protobuf/compiler/code_generator.h" #include "absl/strings/str_cat.h" -#include "google/protobuf/compiler/objectivec/objectivec_enum.h" -#include "google/protobuf/compiler/objectivec/objectivec_extension.h" -#include "google/protobuf/compiler/objectivec/objectivec_helpers.h" -#include "google/protobuf/compiler/objectivec/objectivec_message.h" +#include "google/protobuf/compiler/objectivec/enum.h" +#include "google/protobuf/compiler/objectivec/extension.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/import_writer.h" +#include "google/protobuf/compiler/objectivec/message.h" #include "google/protobuf/io/printer.h" // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.h b/src/google/protobuf/compiler/objectivec/file.h similarity index 98% rename from src/google/protobuf/compiler/objectivec/objectivec_file.h rename to src/google/protobuf/compiler/objectivec/file.h index 5063611923..1af0f54906 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_file.h +++ b/src/google/protobuf/compiler/objectivec/file.h @@ -35,7 +35,7 @@ #include #include #include -#include "google/protobuf/compiler/objectivec/objectivec_options.h" +#include "google/protobuf/compiler/objectivec/options.h" #include "google/protobuf/descriptor.h" #include "google/protobuf/io/printer.h" diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc b/src/google/protobuf/compiler/objectivec/generator.cc similarity index 98% rename from src/google/protobuf/compiler/objectivec/objectivec_generator.cc rename to src/google/protobuf/compiler/objectivec/generator.cc index e5f2fb3d6e..8267d2c827 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc +++ b/src/google/protobuf/compiler/objectivec/generator.cc @@ -28,7 +28,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "google/protobuf/compiler/objectivec/objectivec_generator.h" +#include "google/protobuf/compiler/objectivec/generator.h" #include #include @@ -38,8 +38,9 @@ #include "absl/strings/ascii.h" #include "absl/strings/str_split.h" #include "absl/strings/strip.h" -#include "google/protobuf/compiler/objectivec/objectivec_file.h" -#include "google/protobuf/compiler/objectivec/objectivec_helpers.h" +#include "google/protobuf/compiler/objectivec/file.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/compiler/objectivec/helpers.h" #include "google/protobuf/io/printer.h" #include "google/protobuf/io/zero_copy_stream.h" diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.h b/src/google/protobuf/compiler/objectivec/generator.h similarity index 98% rename from src/google/protobuf/compiler/objectivec/objectivec_generator.h rename to src/google/protobuf/compiler/objectivec/generator.h index acd9ce895f..8b4e1292e7 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_generator.h +++ b/src/google/protobuf/compiler/objectivec/generator.h @@ -37,9 +37,8 @@ #include "google/protobuf/compiler/code_generator.h" #include "google/protobuf/descriptor.h" -// clang-format off +// Must be included last #include "google/protobuf/port_def.inc" -// clang-format on namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/objectivec/helpers.cc b/src/google/protobuf/compiler/objectivec/helpers.cc new file mode 100644 index 0000000000..e5604efe48 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/helpers.cc @@ -0,0 +1,395 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/compiler/code_generator.h" +#include "google/protobuf/stubs/strutil.h" +#include "absl/strings/ascii.h" +#include "absl/strings/escaping.h" +#include "absl/strings/str_split.h" +#include "absl/strings/str_replace.h" +#include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/io/printer.h" +#include "google/protobuf/io/zero_copy_stream_impl.h" +#include "google/protobuf/stubs/common.h" + +// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some +// error cases, so it seems to be ok to use as a back door for errors. + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +std::string EscapeTrigraphs(absl::string_view to_escape) { + return absl::StrReplaceAll(to_escape, {{"?", "\\?"}}); +} + +namespace { + +std::string GetZeroEnumNameForFlagType(const FlagType flag_type) { + switch(flag_type) { + case FLAGTYPE_DESCRIPTOR_INITIALIZATION: + return "GPBDescriptorInitializationFlag_None"; + case FLAGTYPE_EXTENSION: + return "GPBExtensionNone"; + case FLAGTYPE_FIELD: + return "GPBFieldNone"; + default: + GOOGLE_LOG(FATAL) << "Can't get here."; + return "0"; + } +} + +std::string GetEnumNameForFlagType(const FlagType flag_type) { + switch(flag_type) { + case FLAGTYPE_DESCRIPTOR_INITIALIZATION: + return "GPBDescriptorInitializationFlags"; + case FLAGTYPE_EXTENSION: + return "GPBExtensionOptions"; + case FLAGTYPE_FIELD: + return "GPBFieldFlags"; + default: + GOOGLE_LOG(FATAL) << "Can't get here."; + return std::string(); + } +} + +std::string HandleExtremeFloatingPoint(std::string val, + bool add_float_suffix) { + if (val == "nan") { + return "NAN"; + } else if (val == "inf") { + return "INFINITY"; + } else if (val == "-inf") { + return "-INFINITY"; + } else { + // float strings with ., e or E need to have f appended + if (add_float_suffix && (val.find('.') != std::string::npos || + val.find('e') != std::string::npos || + val.find('E') != std::string::npos)) { + val += "f"; + } + return val; + } +} + +} // namespace + +std::string GetCapitalizedType(const FieldDescriptor* field) { + switch (field->type()) { + case FieldDescriptor::TYPE_INT32: + return "Int32"; + case FieldDescriptor::TYPE_UINT32: + return "UInt32"; + case FieldDescriptor::TYPE_SINT32: + return "SInt32"; + case FieldDescriptor::TYPE_FIXED32: + return "Fixed32"; + case FieldDescriptor::TYPE_SFIXED32: + return "SFixed32"; + case FieldDescriptor::TYPE_INT64: + return "Int64"; + case FieldDescriptor::TYPE_UINT64: + return "UInt64"; + case FieldDescriptor::TYPE_SINT64: + return "SInt64"; + case FieldDescriptor::TYPE_FIXED64: + return "Fixed64"; + case FieldDescriptor::TYPE_SFIXED64: + return "SFixed64"; + case FieldDescriptor::TYPE_FLOAT: + return "Float"; + case FieldDescriptor::TYPE_DOUBLE: + return "Double"; + case FieldDescriptor::TYPE_BOOL: + return "Bool"; + case FieldDescriptor::TYPE_STRING: + return "String"; + case FieldDescriptor::TYPE_BYTES: + return "Bytes"; + case FieldDescriptor::TYPE_ENUM: + return "Enum"; + case FieldDescriptor::TYPE_GROUP: + return "Group"; + case FieldDescriptor::TYPE_MESSAGE: + return "Message"; + } + + // Some compilers report reaching end of function even though all cases of + // the enum are handed in the switch. + GOOGLE_LOG(FATAL) << "Can't get here."; + return std::string(); +} + +ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type) { + switch (field_type) { + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_SFIXED32: + return OBJECTIVECTYPE_INT32; + + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_FIXED32: + return OBJECTIVECTYPE_UINT32; + + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_SFIXED64: + return OBJECTIVECTYPE_INT64; + + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_FIXED64: + return OBJECTIVECTYPE_UINT64; + + case FieldDescriptor::TYPE_FLOAT: + return OBJECTIVECTYPE_FLOAT; + + case FieldDescriptor::TYPE_DOUBLE: + return OBJECTIVECTYPE_DOUBLE; + + case FieldDescriptor::TYPE_BOOL: + return OBJECTIVECTYPE_BOOLEAN; + + case FieldDescriptor::TYPE_STRING: + return OBJECTIVECTYPE_STRING; + + case FieldDescriptor::TYPE_BYTES: + return OBJECTIVECTYPE_DATA; + + case FieldDescriptor::TYPE_ENUM: + return OBJECTIVECTYPE_ENUM; + + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + return OBJECTIVECTYPE_MESSAGE; + } + + // Some compilers report reaching end of function even though all cases of + // the enum are handed in the switch. + GOOGLE_LOG(FATAL) << "Can't get here."; + return OBJECTIVECTYPE_INT32; +} + +std::string GPBGenericValueFieldName(const FieldDescriptor* field) { + // Returns the field within the GPBGenericValue union to use for the given + // field. + if (field->is_repeated()) { + return "valueMessage"; + } + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + return "valueInt32"; + case FieldDescriptor::CPPTYPE_UINT32: + return "valueUInt32"; + case FieldDescriptor::CPPTYPE_INT64: + return "valueInt64"; + case FieldDescriptor::CPPTYPE_UINT64: + return "valueUInt64"; + case FieldDescriptor::CPPTYPE_FLOAT: + return "valueFloat"; + case FieldDescriptor::CPPTYPE_DOUBLE: + return "valueDouble"; + case FieldDescriptor::CPPTYPE_BOOL: + return "valueBool"; + case FieldDescriptor::CPPTYPE_STRING: + if (field->type() == FieldDescriptor::TYPE_BYTES) { + return "valueData"; + } else { + return "valueString"; + } + case FieldDescriptor::CPPTYPE_ENUM: + return "valueEnum"; + case FieldDescriptor::CPPTYPE_MESSAGE: + return "valueMessage"; + } + + // Some compilers report reaching end of function even though all cases of + // the enum are handed in the switch. + GOOGLE_LOG(FATAL) << "Can't get here."; + return std::string(); +} + + +std::string DefaultValue(const FieldDescriptor* field) { + // Repeated fields don't have defaults. + if (field->is_repeated()) { + return "nil"; + } + + // Switch on cpp_type since we need to know which default_value_* method + // of FieldDescriptor to call. + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + // gcc and llvm reject the decimal form of kint32min and kint64min. + if (field->default_value_int32() == INT_MIN) { + return "-0x80000000"; + } + return absl::StrCat(field->default_value_int32()); + case FieldDescriptor::CPPTYPE_UINT32: + return absl::StrCat(field->default_value_uint32()) + "U"; + case FieldDescriptor::CPPTYPE_INT64: + // gcc and llvm reject the decimal form of kint32min and kint64min. + if (field->default_value_int64() == LLONG_MIN) { + return "-0x8000000000000000LL"; + } + return absl::StrCat(field->default_value_int64()) + "LL"; + case FieldDescriptor::CPPTYPE_UINT64: + return absl::StrCat(field->default_value_uint64()) + "ULL"; + case FieldDescriptor::CPPTYPE_DOUBLE: + return HandleExtremeFloatingPoint( + SimpleDtoa(field->default_value_double()), false); + case FieldDescriptor::CPPTYPE_FLOAT: + return HandleExtremeFloatingPoint( + SimpleFtoa(field->default_value_float()), true); + case FieldDescriptor::CPPTYPE_BOOL: + return field->default_value_bool() ? "YES" : "NO"; + case FieldDescriptor::CPPTYPE_STRING: { + const bool has_default_value = field->has_default_value(); + const std::string& default_string = field->default_value_string(); + if (!has_default_value || default_string.length() == 0) { + // If the field is defined as being the empty string, + // then we will just assign to nil, as the empty string is the + // default for both strings and data. + return "nil"; + } + if (field->type() == FieldDescriptor::TYPE_BYTES) { + // We want constant fields in our data structures so we can + // declare them as static. To achieve this we cheat and stuff + // a escaped c string (prefixed with a length) into the data + // field, and cast it to an (NSData*) so it will compile. + // The runtime library knows how to handle it. + + // Must convert to a standard byte order for packing length into + // a cstring. + uint32_t length = ghtonl(default_string.length()); + std::string bytes((const char*)&length, sizeof(length)); + bytes.append(default_string); + return "(NSData*)\"" + EscapeTrigraphs(absl::CEscape(bytes)) + "\""; + } else { + return "@\"" + EscapeTrigraphs(absl::CEscape(default_string)) + "\""; + } + } + case FieldDescriptor::CPPTYPE_ENUM: + return EnumValueName(field->default_value_enum()); + case FieldDescriptor::CPPTYPE_MESSAGE: + return "nil"; + } + + // Some compilers report reaching end of function even though all cases of + // the enum are handed in the switch. + GOOGLE_LOG(FATAL) << "Can't get here."; + return std::string(); +} + +std::string BuildFlagsString(const FlagType flag_type, + const std::vector& strings) { + if (strings.empty()) { + return GetZeroEnumNameForFlagType(flag_type); + } else if (strings.size() == 1) { + return strings[0]; + } + std::string string("(" + GetEnumNameForFlagType(flag_type) + ")("); + for (size_t i = 0; i != strings.size(); ++i) { + if (i > 0) { + string.append(" | "); + } + string.append(strings[i]); + } + string.append(")"); + return string; +} + +std::string ObjCClass(const std::string& class_name) { + return std::string("GPBObjCClass(") + class_name + ")"; +} + +std::string ObjCClassDeclaration(const std::string& class_name) { + return std::string("GPBObjCClassDeclaration(") + class_name + ");"; +} + +std::string BuildCommentsString(const SourceLocation& location, + bool prefer_single_line) { + const std::string& comments = location.leading_comments.empty() + ? location.trailing_comments + : location.leading_comments; + std::vector lines; + lines = absl::StrSplit(comments, "\n", absl::AllowEmpty()); + while (!lines.empty() && lines.back().empty()) { + lines.pop_back(); + } + // If there are no comments, just return an empty string. + if (lines.empty()) { + return ""; + } + + std::string prefix; + std::string suffix; + std::string final_comments; + std::string epilogue; + + bool add_leading_space = false; + + if (prefer_single_line && lines.size() == 1) { + prefix = "/** "; + suffix = " */\n"; + } else { + prefix = "* "; + suffix = "\n"; + final_comments += "/**\n"; + epilogue = " **/\n"; + add_leading_space = true; + } + + for (size_t i = 0; i < lines.size(); i++) { + std::string line = absl::StrReplaceAll( + absl::StripPrefix(lines[i], " "), + {// HeaderDoc and appledoc use '\' and '@' for markers; escape them. + {"\\", "\\\\"}, + {"@", "\\@"}, + // Decouple / from * to not have inline comments inside comments. + {"/*", "/\\*"}, + {"*/", "*\\/"}}); + line = prefix + line; + absl::StripAsciiWhitespace(&line); + // If not a one line, need to add the first space before *, as + // absl::StripAsciiWhitespace would have removed it. + line = (add_leading_space ? " " : "") + line; + final_comments += line + suffix; + } + final_comments += epilogue; + return final_comments; +} + + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/helpers.h b/src/google/protobuf/compiler/objectivec/helpers.h new file mode 100644 index 0000000000..ce7cc9aae3 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/helpers.h @@ -0,0 +1,143 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Helper functions for generating ObjectiveC code. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__ + +#include +#include + +#include "google/protobuf/descriptor.h" +#include "google/protobuf/descriptor.pb.h" + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +inline bool HasPreservingUnknownEnumSemantics(const FileDescriptor* file) { + return file->syntax() == FileDescriptor::SYNTAX_PROTO3; +} + +// Escape C++ trigraphs by escaping question marks to "\?". +std::string EscapeTrigraphs(absl::string_view to_escape); + +enum ObjectiveCType { + OBJECTIVECTYPE_INT32, + OBJECTIVECTYPE_UINT32, + OBJECTIVECTYPE_INT64, + OBJECTIVECTYPE_UINT64, + OBJECTIVECTYPE_FLOAT, + OBJECTIVECTYPE_DOUBLE, + OBJECTIVECTYPE_BOOLEAN, + OBJECTIVECTYPE_STRING, + OBJECTIVECTYPE_DATA, + OBJECTIVECTYPE_ENUM, + OBJECTIVECTYPE_MESSAGE +}; + +enum FlagType { + FLAGTYPE_DESCRIPTOR_INITIALIZATION, + FLAGTYPE_EXTENSION, + FLAGTYPE_FIELD +}; + +std::string GetCapitalizedType(const FieldDescriptor* field); + +ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type); + +inline ObjectiveCType GetObjectiveCType(const FieldDescriptor* field) { + return GetObjectiveCType(field->type()); +} + +std::string GPBGenericValueFieldName(const FieldDescriptor* field); +std::string DefaultValue(const FieldDescriptor* field); + +std::string BuildFlagsString(const FlagType type, const std::vector& strings); + +// Returns a symbol that can be used in C code to refer to an Objective C +// class without initializing the class. +std::string ObjCClass(const std::string& class_name); + +// Declares an Objective C class without initializing the class so that it can +// be refrerred to by ObjCClass. +std::string ObjCClassDeclaration(const std::string& class_name); + +// Builds HeaderDoc/appledoc style comments out of the comments in the .proto +// file. +std::string BuildCommentsString(const SourceLocation& location, + bool prefer_single_line); + +template +std::string GetOptionalDeprecatedAttribute(const TDescriptor* descriptor, + const FileDescriptor* file = NULL, + bool preSpace = true, + bool postNewline = false) { + bool isDeprecated = descriptor->options().deprecated(); + // The file is only passed when checking Messages & Enums, so those types + // get tagged. At the moment, it doesn't seem to make sense to tag every + // field or enum value with when the file is deprecated. + bool isFileLevelDeprecation = false; + if (!isDeprecated && file) { + isFileLevelDeprecation = file->options().deprecated(); + isDeprecated = isFileLevelDeprecation; + } + if (isDeprecated) { + std::string message; + const FileDescriptor* sourceFile = descriptor->file(); + if (isFileLevelDeprecation) { + message = sourceFile->name() + " is deprecated."; + } else { + message = descriptor->full_name() + " is deprecated (see " + + sourceFile->name() + ")."; + } + + std::string result = std::string("GPB_DEPRECATED_MSG(\"") + message + "\")"; + if (preSpace) { + result.insert(0, " "); + } + if (postNewline) { + result.append("\n"); + } + return result; + } else { + return ""; + } +} + + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__ diff --git a/src/google/protobuf/compiler/objectivec/import_writer.cc b/src/google/protobuf/compiler/objectivec/import_writer.cc new file mode 100644 index 0000000000..3a058a916f --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/import_writer.cc @@ -0,0 +1,264 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/compiler/objectivec/import_writer.h" +#include "google/protobuf/compiler/objectivec/line_consumer.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/io/printer.h" +#include "absl/strings/ascii.h" + +// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some +// error cases, so it seems to be ok to use as a back door for errors. + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +namespace { + +class ProtoFrameworkCollector : public LineConsumer { + public: + ProtoFrameworkCollector(std::map* inout_proto_file_to_framework_name) + : map_(inout_proto_file_to_framework_name) {} + + virtual bool ConsumeLine(const absl::string_view& line, std::string* out_error) override; + + private: + std::map* map_; +}; + +bool ProtoFrameworkCollector::ConsumeLine( + const absl::string_view& line, std::string* out_error) { + int offset = line.find(':'); + if (offset == absl::string_view::npos) { + *out_error = + std::string("Framework/proto file mapping line without colon sign: '") + + std::string(line) + "'."; + return false; + } + absl::string_view framework_name = absl::StripAsciiWhitespace(line.substr(0, offset)); + absl::string_view proto_file_list = absl::StripAsciiWhitespace(line.substr(offset + 1)); + + int start = 0; + while (start < proto_file_list.length()) { + offset = proto_file_list.find(',', start); + if (offset == absl::string_view::npos) { + offset = proto_file_list.length(); + } + + absl::string_view proto_file = + absl::StripAsciiWhitespace(proto_file_list.substr(start, offset - start)); + if (!proto_file.empty()) { + std::map::iterator existing_entry = + map_->find(std::string(proto_file)); + if (existing_entry != map_->end()) { + std::cerr << "warning: duplicate proto file reference, replacing " + "framework entry for '" + << std::string(proto_file) << "' with '" << std::string(framework_name) + << "' (was '" << existing_entry->second << "')." << std::endl; + std::cerr.flush(); + } + + if (proto_file.find(' ') != absl::string_view::npos) { + std::cerr << "note: framework mapping file had a proto file with a " + "space in, hopefully that isn't a missing comma: '" + << std::string(proto_file) << "'" << std::endl; + std::cerr.flush(); + } + + (*map_)[std::string(proto_file)] = std::string(framework_name); + } + + start = offset + 1; + } + + return true; +} + +} // namespace + +ImportWriter::ImportWriter( + const std::string& generate_for_named_framework, + const std::string& named_framework_to_proto_path_mappings_path, + const std::string& runtime_import_prefix, bool include_wkt_imports) + : generate_for_named_framework_(generate_for_named_framework), + named_framework_to_proto_path_mappings_path_( + named_framework_to_proto_path_mappings_path), + runtime_import_prefix_(runtime_import_prefix), + include_wkt_imports_(include_wkt_imports), + need_to_parse_mapping_file_(true) {} + +ImportWriter::~ImportWriter() {} + +void ImportWriter::AddFile(const FileDescriptor* file, + const std::string& header_extension) { + if (IsProtobufLibraryBundledProtoFile(file)) { + // The imports of the WKTs are only needed within the library itself, + // in other cases, they get skipped because the generated code already + // import GPBProtocolBuffers.h and hence proves them. + if (include_wkt_imports_) { + const std::string header_name = + "GPB" + FilePathBasename(file) + header_extension; + protobuf_imports_.push_back(header_name); + } + return; + } + + // Lazy parse any mappings. + if (need_to_parse_mapping_file_) { + ParseFrameworkMappings(); + } + + std::map::iterator proto_lookup = + proto_file_to_framework_name_.find(file->name()); + if (proto_lookup != proto_file_to_framework_name_.end()) { + other_framework_imports_.push_back( + proto_lookup->second + "/" + + FilePathBasename(file) + header_extension); + return; + } + + if (!generate_for_named_framework_.empty()) { + other_framework_imports_.push_back( + generate_for_named_framework_ + "/" + + FilePathBasename(file) + header_extension); + return; + } + + other_imports_.push_back(FilePath(file) + header_extension); +} + +void ImportWriter::Print(io::Printer* printer) const { + bool add_blank_line = false; + + if (!protobuf_imports_.empty()) { + PrintRuntimeImports(printer, protobuf_imports_, runtime_import_prefix_); + add_blank_line = true; + } + + if (!other_framework_imports_.empty()) { + if (add_blank_line) { + printer->Print("\n"); + } + + for (std::vector::const_iterator iter = + other_framework_imports_.begin(); + iter != other_framework_imports_.end(); ++iter) { + printer->Print( + "#import <$header$>\n", + "header", *iter); + } + + add_blank_line = true; + } + + if (!other_imports_.empty()) { + if (add_blank_line) { + printer->Print("\n"); + } + + for (std::vector::const_iterator iter = other_imports_.begin(); + iter != other_imports_.end(); ++iter) { + printer->Print( + "#import \"$header$\"\n", + "header", *iter); + } + } +} + +void ImportWriter::PrintRuntimeImports( + io::Printer* printer, const std::vector& header_to_import, + const std::string& runtime_import_prefix, bool default_cpp_symbol) { + // Given an override, use that. + if (!runtime_import_prefix.empty()) { + for (const auto& header : header_to_import) { + printer->Print( + " #import \"$import_prefix$/$header$\"\n", + "import_prefix", runtime_import_prefix, + "header", header); + } + return; + } + + const std::string framework_name(ProtobufLibraryFrameworkName); + const std::string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name)); + + if (default_cpp_symbol) { + printer->Print( + "// This CPP symbol can be defined to use imports that match up to the framework\n" + "// imports needed when using CocoaPods.\n" + "#if !defined($cpp_symbol$)\n" + " #define $cpp_symbol$ 0\n" + "#endif\n" + "\n", + "cpp_symbol", cpp_symbol); + } + + printer->Print( + "#if $cpp_symbol$\n", + "cpp_symbol", cpp_symbol); + for (const auto& header : header_to_import) { + printer->Print( + " #import <$framework_name$/$header$>\n", + "framework_name", framework_name, + "header", header); + } + printer->Print( + "#else\n"); + for (const auto& header : header_to_import) { + printer->Print( + " #import \"$header$\"\n", + "header", header); + } + printer->Print( + "#endif\n"); +} + +void ImportWriter::ParseFrameworkMappings() { + need_to_parse_mapping_file_ = false; + if (named_framework_to_proto_path_mappings_path_.empty()) { + return; // Nothing to do. + } + + ProtoFrameworkCollector collector(&proto_file_to_framework_name_); + std::string parse_error; + if (!ParseSimpleFile(named_framework_to_proto_path_mappings_path_, + &collector, &parse_error)) { + std::cerr << "error parsing " << named_framework_to_proto_path_mappings_path_ + << " : " << parse_error << std::endl; + std::cerr.flush(); + } +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/import_writer.h b/src/google/protobuf/compiler/objectivec/import_writer.h new file mode 100644 index 0000000000..7c8b29729e --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/import_writer.h @@ -0,0 +1,84 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_IMPORT_WRITER_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_IMPORT_WRITER_H__ + +#include +#include + +#include "google/protobuf/descriptor.h" +#include "google/protobuf/descriptor.pb.h" + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +// Helper class for parsing framework import mappings and generating +// import statements. +class ImportWriter { + public: + ImportWriter(const std::string& generate_for_named_framework, + const std::string& named_framework_to_proto_path_mappings_path, + const std::string& runtime_import_prefix, + bool include_wkt_imports); + ~ImportWriter(); + + void AddFile(const FileDescriptor* file, const std::string& header_extension); + void Print(io::Printer* printer) const; + + static void PrintRuntimeImports(io::Printer* printer, + const std::vector& header_to_import, + const std::string& runtime_import_prefix, + bool default_cpp_symbol = false); + + private: + void ParseFrameworkMappings(); + + const std::string generate_for_named_framework_; + const std::string named_framework_to_proto_path_mappings_path_; + const std::string runtime_import_prefix_; + const bool include_wkt_imports_; + std::map proto_file_to_framework_name_; + bool need_to_parse_mapping_file_; + + std::vector protobuf_imports_; + std::vector other_framework_imports_; + std::vector other_imports_; +}; + + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_IMPORT_WRITER_H__ diff --git a/src/google/protobuf/compiler/objectivec/line_consumer.cc b/src/google/protobuf/compiler/objectivec/line_consumer.cc new file mode 100644 index 0000000000..2026c2826d --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/line_consumer.cc @@ -0,0 +1,216 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef _MSC_VER +#include +#endif +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "absl/strings/ascii.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_split.h" +#include "google/protobuf/compiler/objectivec/line_consumer.h" +#include "google/protobuf/io/io_win32.h" +#include "google/protobuf/io/zero_copy_stream_impl.h" + +// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some +// error cases, so it seems to be ok to use as a back door for errors. + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +// is transitively included in this file. Import the functions explicitly +// in this port namespace to avoid ambiguous definition. +namespace posix { +#ifdef _WIN32 +using google::protobuf::io::win32::open; +#else // !_WIN32 +using ::open; +#endif // _WIN32 +} // namespace posix + +namespace { + +bool ascii_isnewline(char c) { + return c == '\n' || c == '\r'; +} + +bool ReadLine(absl::string_view* input, absl::string_view* line) { + for (int len = 0; len < input->size(); ++len) { + if (ascii_isnewline((*input)[len])) { + *line = absl::string_view(input->data(), len); + ++len; // advance over the newline + *input = absl::string_view(input->data() + len, input->size() - len); + return true; + } + } + return false; // Ran out of input with no newline. +} + +void RemoveComment(absl::string_view* input) { + int offset = input->find('#'); + if (offset != absl::string_view::npos) { + input->remove_suffix(input->length() - offset); + } +} + +class Parser { + public: + Parser(LineConsumer* line_consumer) + : line_consumer_(line_consumer), line_(0) {} + + // Feeds in some input, parse what it can, returning success/failure. Calling + // again after an error is undefined. + bool ParseChunk(absl::string_view chunk, std::string* out_error); + + // Should be called to finish parsing (after all input has been provided via + // successful calls to ParseChunk(), calling after a ParseChunk() failure is + // undefined). Returns success/failure. + bool Finish(std::string* out_error); + + int last_line() const { return line_; } + + private: + LineConsumer* line_consumer_; + int line_; + std::string leftover_; +}; + +bool Parser::ParseChunk(absl::string_view chunk, std::string* out_error) { + absl::string_view full_chunk; + if (!leftover_.empty()) { + leftover_ += std::string(chunk); + full_chunk = absl::string_view(leftover_); + } else { + full_chunk = chunk; + } + + absl::string_view line; + while (ReadLine(&full_chunk, &line)) { + ++line_; + RemoveComment(&line); + line = absl::StripAsciiWhitespace(line); + if (!line.empty() && !line_consumer_->ConsumeLine(line, out_error)) { + if (out_error->empty()) { + *out_error = "ConsumeLine failed without setting an error."; + } + leftover_.clear(); + return false; + } + } + + if (full_chunk.empty()) { + leftover_.clear(); + } else { + leftover_ = std::string(full_chunk); + } + return true; +} + +bool Parser::Finish(std::string* out_error) { + // If there is still something to go, flush it with a newline. + if (!leftover_.empty() && !ParseChunk("\n", out_error)) { + return false; + } + // This really should never fail if ParseChunk succeeded, but check to be sure. + if (!leftover_.empty()) { + *out_error = "ParseSimple Internal error: finished with pending data."; + return false; + } + return true; +} + +std::string FullErrorString(const std::string& name, int line_num, const std::string& msg) { + return std::string("error: ") + name + " Line " + absl::StrCat(line_num) + ", " + msg; +} + +} // namespace + +LineConsumer::LineConsumer() {} + +LineConsumer::~LineConsumer() {} + +bool ParseSimpleFile(const std::string& path, LineConsumer* line_consumer, + std::string* out_error) { + int fd; + do { + fd = posix::open(path.c_str(), O_RDONLY); + } while (fd < 0 && errno == EINTR); + if (fd < 0) { + *out_error = std::string("error: Unable to open \"") + path + "\", " + + strerror(errno); + return false; + } + io::FileInputStream file_stream(fd); + file_stream.SetCloseOnDelete(true); + + return ParseSimpleStream(file_stream, path, line_consumer, out_error); +} + +bool ParseSimpleStream(io::ZeroCopyInputStream& input_stream, + const std::string& stream_name, + LineConsumer* line_consumer, + std::string* out_error) { + std::string local_error; + Parser parser(line_consumer); + const void* buf; + int buf_len; + while (input_stream.Next(&buf, &buf_len)) { + if (buf_len == 0) { + continue; + } + + if (!parser.ParseChunk(absl::string_view(static_cast(buf), buf_len), + &local_error)) { + *out_error = FullErrorString(stream_name, parser.last_line(), local_error); + return false; + } + } + if (!parser.Finish(&local_error)) { + *out_error = FullErrorString(stream_name, parser.last_line(), local_error); + return false; + } + return true; +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/line_consumer.h b/src/google/protobuf/compiler/objectivec/line_consumer.h new file mode 100644 index 0000000000..15a935b6b0 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/line_consumer.h @@ -0,0 +1,74 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_LINE_CONSUMER_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_LINE_CONSUMER_H__ + +#include +#include + +#include "google/protobuf/io/zero_copy_stream.h" + +// Must be included last +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +// TODO(b/250947994): PROTOC_EXPORT is only used to allow the CMake build to +// find/link these in the unittest, this is not public api. + +// Helper for parsing simple files. +class PROTOC_EXPORT LineConsumer { + public: + LineConsumer(); + virtual ~LineConsumer(); + virtual bool ConsumeLine(const absl::string_view& line, std::string* out_error) = 0; +}; + +bool PROTOC_EXPORT ParseSimpleFile(const std::string& path, + LineConsumer* line_consumer, + std::string* out_error); + +bool PROTOC_EXPORT ParseSimpleStream(io::ZeroCopyInputStream& input_stream, + const std::string& stream_name, + LineConsumer* line_consumer, + std::string* out_error); + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include "google/protobuf/port_undef.inc" + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_LINE_CONSUMER_H__ diff --git a/src/google/protobuf/compiler/objectivec/line_consumer_unittest.cc b/src/google/protobuf/compiler/objectivec/line_consumer_unittest.cc new file mode 100644 index 0000000000..2513b6f4fe --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/line_consumer_unittest.cc @@ -0,0 +1,174 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/compiler/objectivec/line_consumer.h" +#include "google/protobuf/io/zero_copy_stream_impl_lite.h" +#include "absl/strings/str_cat.h" + +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { +namespace { + +class TestLineCollector : public LineConsumer { + public: + explicit TestLineCollector(std::vector* inout_lines, + const std::string* reject_line = nullptr, + bool skip_msg = false) + : lines_(inout_lines), reject_(reject_line), skip_msg_(skip_msg) {} + + bool ConsumeLine(const absl::string_view& line, std::string* out_error) override { + if (reject_ && *reject_ == line) { + if (!skip_msg_) { + *out_error = std::string("Rejected '") + *reject_ + "'"; + } + return false; + } + if (lines_) { + lines_->emplace_back(line); + } + return true; + } + + private: + std::vector* lines_; + const std::string* reject_; + bool skip_msg_; +}; + +const int kBlockSizes[] = {-1, 1, 2, 5, 64}; +const int kBlockSizeCount = ABSL_ARRAYSIZE(kBlockSizes); + +TEST(ObjCHelper, ParseSimple_BasicsSuccess) { + const std::vector>> tests = { + {"", {}}, + {"a", {"a"}}, + {"a c", {"a c"}}, + {" a c ", {"a c"}}, + {"\ta c ", {"a c"}}, + {"abc\n", {"abc"}}, + {"abc\nd f", {"abc", "d f"}}, + {"\n abc \n def \n\n", {"abc", "def"}}, + }; + + for (const auto& test : tests) { + for (int i = 0; i < kBlockSizeCount; i++) { + io::ArrayInputStream input(test.first.data(), test.first.size(), kBlockSizes[i]); + std::string err_str; + std::vector lines; + TestLineCollector collector(&lines); + EXPECT_TRUE(ParseSimpleStream(input, "dummy", &collector, &err_str)); + EXPECT_EQ(lines, test.second); + EXPECT_TRUE(err_str.empty()); + } + } +} + +TEST(ObjCHelper, ParseSimple_DropsComments) { + const std::vector>> tests = { + {"# nothing", {}}, + {"#", {}}, + {"##", {}}, + {"\n# nothing\n", {}}, + {"a # same line", {"a"}}, + {"a # same line\n", {"a"}}, + {"a\n# line\nc", {"a", "c"}}, + {"# n o t # h i n g #", {}}, + {"## n o # t h i n g #", {}}, + {"a# n o t # h i n g #", {"a"}}, + {"a\n## n o # t h i n g #", {"a"}}, + }; + + for (const auto& test : tests) { + for (int i = 0; i < kBlockSizeCount; i++) { + io::ArrayInputStream input(test.first.data(), test.first.size(), kBlockSizes[i]); + std::string err_str; + std::vector lines; + TestLineCollector collector(&lines); + EXPECT_TRUE(ParseSimpleStream(input, "dummy", &collector, &err_str)); + EXPECT_EQ(lines, test.second); + EXPECT_TRUE(err_str.empty()); + } + } +} + +TEST(ObjCHelper, ParseSimple_RejectLines) { + const std::vector> tests = { + std::make_tuple("a\nb\nc", "a", 1), + std::make_tuple("a\nb\nc", "b", 2), + std::make_tuple("a\nb\nc", "c", 3), + std::make_tuple("a\nb\nc\n", "c", 3), + }; + + for (const auto& test : tests) { + for (int i = 0; i < kBlockSizeCount; i++) { + io::ArrayInputStream input(std::get<0>(test).data(), std::get<0>(test).size(), + kBlockSizes[i]); + std::string err_str; + TestLineCollector collector(nullptr, &std::get<1>(test)); + EXPECT_FALSE(ParseSimpleStream(input, "dummy", &collector, &err_str)); + std::string expected_err = + absl::StrCat("error: dummy Line ", std::get<2>(test), ", Rejected '", std::get<1>(test), "'"); + EXPECT_EQ(err_str, expected_err); + } + } +} + +TEST(ObjCHelper, ParseSimple_RejectLinesNoMessage) { + const std::vector> tests = { + std::make_tuple("a\nb\nc", "a", 1), + std::make_tuple("a\nb\nc", "b", 2), + std::make_tuple("a\nb\nc", "c", 3), + std::make_tuple("a\nb\nc\n", "c", 3), + }; + + for (const auto& test : tests) { + for (int i = 0; i < kBlockSizeCount; i++) { + io::ArrayInputStream input(std::get<0>(test).data(), std::get<0>(test).size(), + kBlockSizes[i]); + std::string err_str; + TestLineCollector collector(nullptr, &std::get<1>(test), true /* skip msg */); + EXPECT_FALSE(ParseSimpleStream(input, "dummy", &collector, &err_str)); + std::string expected_err = + absl::StrCat("error: dummy Line ", std::get<2>(test), + ", ConsumeLine failed without setting an error."); + EXPECT_EQ(err_str, expected_err); + } + } +} + +} // namespace +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc b/src/google/protobuf/compiler/objectivec/map_field.cc similarity index 97% rename from src/google/protobuf/compiler/objectivec/objectivec_map_field.cc rename to src/google/protobuf/compiler/objectivec/map_field.cc index 087bd8fb2d..e11794a77e 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc +++ b/src/google/protobuf/compiler/objectivec/map_field.cc @@ -31,8 +31,9 @@ #include #include -#include "google/protobuf/compiler/objectivec/objectivec_map_field.h" -#include "google/protobuf/compiler/objectivec/objectivec_helpers.h" +#include "google/protobuf/compiler/objectivec/map_field.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/compiler/objectivec/helpers.h" #include "google/protobuf/io/printer.h" namespace google { diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h b/src/google/protobuf/compiler/objectivec/map_field.h similarity index 97% rename from src/google/protobuf/compiler/objectivec/objectivec_map_field.h rename to src/google/protobuf/compiler/objectivec/map_field.h index 20c538e3bb..bea9f6dd34 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h +++ b/src/google/protobuf/compiler/objectivec/map_field.h @@ -34,7 +34,7 @@ #include #include -#include "google/protobuf/compiler/objectivec/objectivec_field.h" +#include "google/protobuf/compiler/objectivec/field.h" namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/src/google/protobuf/compiler/objectivec/message.cc similarity index 98% rename from src/google/protobuf/compiler/objectivec/objectivec_message.cc rename to src/google/protobuf/compiler/objectivec/message.cc index 98161494da..9169ecddfc 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message.cc +++ b/src/google/protobuf/compiler/objectivec/message.cc @@ -28,7 +28,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "google/protobuf/compiler/objectivec/objectivec_message.h" +#include "google/protobuf/compiler/objectivec/message.h" #include #include @@ -36,9 +36,11 @@ #include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" -#include "google/protobuf/compiler/objectivec/objectivec_enum.h" -#include "google/protobuf/compiler/objectivec/objectivec_extension.h" -#include "google/protobuf/compiler/objectivec/objectivec_helpers.h" +#include "google/protobuf/compiler/objectivec/enum.h" +#include "google/protobuf/compiler/objectivec/extension.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/text_format_decode_data.h" #include "google/protobuf/descriptor.pb.h" #include "google/protobuf/io/printer.h" @@ -48,6 +50,11 @@ namespace compiler { namespace objectivec { namespace { + +bool IsMapEntryMessage(const Descriptor* descriptor) { + return descriptor->options().map_entry(); +} + struct FieldOrderingByNumber { inline bool operator()(const FieldDescriptor* a, const FieldDescriptor* b) const { @@ -165,6 +172,7 @@ const FieldDescriptor** SortFieldsByStorageSize(const Descriptor* descriptor) { FieldOrderingByStorageSize()); return fields; } + } // namespace MessageGenerator::MessageGenerator(const std::string& root_classname, diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.h b/src/google/protobuf/compiler/objectivec/message.h similarity index 96% rename from src/google/protobuf/compiler/objectivec/objectivec_message.h rename to src/google/protobuf/compiler/objectivec/message.h index 641a518638..7eb8c2df98 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message.h +++ b/src/google/protobuf/compiler/objectivec/message.h @@ -34,8 +34,8 @@ #include #include #include -#include "google/protobuf/compiler/objectivec/objectivec_field.h" -#include "google/protobuf/compiler/objectivec/objectivec_oneof.h" +#include "google/protobuf/compiler/objectivec/field.h" +#include "google/protobuf/compiler/objectivec/oneof.h" #include "google/protobuf/descriptor.h" #include "google/protobuf/io/printer.h" diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc b/src/google/protobuf/compiler/objectivec/message_field.cc similarity index 96% rename from src/google/protobuf/compiler/objectivec/objectivec_message_field.cc rename to src/google/protobuf/compiler/objectivec/message_field.cc index e889c6ef5e..b9dd6c02fb 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc +++ b/src/google/protobuf/compiler/objectivec/message_field.cc @@ -31,8 +31,9 @@ #include #include -#include "google/protobuf/compiler/objectivec/objectivec_message_field.h" -#include "google/protobuf/compiler/objectivec/objectivec_helpers.h" +#include "google/protobuf/compiler/objectivec/message_field.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/compiler/objectivec/helpers.h" #include "google/protobuf/io/printer.h" namespace google { diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.h b/src/google/protobuf/compiler/objectivec/message_field.h similarity index 98% rename from src/google/protobuf/compiler/objectivec/objectivec_message_field.h rename to src/google/protobuf/compiler/objectivec/message_field.h index 19f23a29e7..7ed1cf24ff 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message_field.h +++ b/src/google/protobuf/compiler/objectivec/message_field.h @@ -34,7 +34,7 @@ #include #include -#include "google/protobuf/compiler/objectivec/objectivec_field.h" +#include "google/protobuf/compiler/objectivec/field.h" namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/objectivec/method_dump.sh b/src/google/protobuf/compiler/objectivec/method_dump.sh index 193825dbc1..6592212814 100755 --- a/src/google/protobuf/compiler/objectivec/method_dump.sh +++ b/src/google/protobuf/compiler/objectivec/method_dump.sh @@ -1,7 +1,7 @@ #!/bin/bash -# Updates objectivec_nsobject_methods.h by generating a list of all of the properties -# and methods on NSObject that Protobufs should not overload from iOS and macOS combined. +# Updates nsobject_methods.h by generating a list of all of the properties and +# methods on NSObject that Protobufs should not overload from iOS and macOS combined. # # The rules: # - No property should ever be overloaded. @@ -110,7 +110,7 @@ END_FOOTER ) # Check to make sure we are updating the correct file. -if [[ ! -e "objectivec_nsobject_methods.h" ]]; then +if [[ ! -e "nsobject_methods.h" ]]; then echo "error: Must be run in the src/google/protobuf/compiler/objectivec directory" exit 1 fi @@ -154,7 +154,7 @@ echo $"$file_footer" >> "$temp_dir"/methods_sorted.txt # Check for differences. Turn off error checking because we expect diff to fail when # there are no differences. set +e -diff_out=$(diff -I "^//.*$" "$temp_dir"/methods_sorted.txt objectivec_nsobject_methods.h) +diff_out=$(diff -I "^//.*$" "$temp_dir"/methods_sorted.txt nsobject_methods.h) removed_methods=$(echo "$diff_out" | grep '^>.*$') set -e if [[ -n "$removed_methods" ]]; then @@ -168,12 +168,12 @@ if [[ -n "$removed_methods" ]]; then echo "$removed_methods" echo "" echo "New Version: $temp_dir/methods_sorted.txt" - echo "Old Version: objectivec_nsobject_methods.h" + echo "Old Version: nsobject_methods.h" exit 1 fi if [[ -n "$diff_out" ]]; then echo "Added Methods:" echo "$(echo "$diff_out" | grep '^<.*$' | sed -e 's/^< "\(.*\)",$/ \1/')" fi; -cp "$temp_dir"/methods_sorted.txt objectivec_nsobject_methods.h +cp "$temp_dir"/methods_sorted.txt nsobject_methods.h rm -rf "$temp_dir" diff --git a/src/google/protobuf/compiler/objectivec/names.cc b/src/google/protobuf/compiler/objectivec/names.cc index 5ae447fe4b..84fb4dd17d 100644 --- a/src/google/protobuf/compiler/objectivec/names.cc +++ b/src/google/protobuf/compiler/objectivec/names.cc @@ -28,13 +28,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef _MSC_VER -#include -#endif -#include -#include -#include - #include #include #include @@ -43,21 +36,13 @@ #include #include "google/protobuf/compiler/code_generator.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/ascii.h" -#include "absl/strings/escaping.h" -#include "absl/strings/str_replace.h" #include "absl/strings/str_split.h" -#include "absl/strings/strip.h" +#include "google/protobuf/compiler/objectivec/line_consumer.h" #include "google/protobuf/compiler/objectivec/names.h" -#include "google/protobuf/compiler/objectivec/objectivec_nsobject_methods.h" +#include "google/protobuf/compiler/objectivec/nsobject_methods.h" #include "google/protobuf/descriptor.pb.h" -#include "google/protobuf/io/coded_stream.h" -#include "google/protobuf/io/io_win32.h" -#include "google/protobuf/io/printer.h" #include "google/protobuf/io/zero_copy_stream_impl.h" -#include "google/protobuf/port.h" -#include "google/protobuf/stubs/common.h" // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some // error cases, so it seems to be ok to use as a back door for errors. @@ -67,16 +52,6 @@ namespace protobuf { namespace compiler { namespace objectivec { -// is transitively included in this file. Import the functions explicitly -// in this port namespace to avoid ambiguous definition. -namespace posix { -#ifdef _WIN32 -using google::protobuf::io::win32::open; -#else // !_WIN32 -using ::open; -#endif // _WIN32 -} // namespace posix - namespace { bool BoolFromEnvVar(const char* env_var, bool default_value) { @@ -267,24 +242,6 @@ void SetForcedPackagePrefix(const std::string& prefix) { g_prefix_mode.set_forced_package_prefix(prefix); } -Options::Options() { - // While there are generator options, also support env variables to help with - // build systems where it isn't as easy to hook in for add the generation - // options when invoking protoc. - const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES"); - if (file_path) { - expected_prefixes_path = file_path; - } - const char* suppressions = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES_SUPPRESSIONS"); - if (suppressions) { - expected_prefixes_suppressions = - absl::StrSplit(suppressions, ";", absl::SkipEmpty()); - } - prefixes_must_be_registered = - BoolFromEnvVar("GPB_OBJC_PREFIXES_MUST_BE_REGISTERED", false); - require_prefixes = BoolFromEnvVar("GPB_OBJC_REQUIRE_PREFIXES", false); -} - namespace { std::unordered_set MakeWordsMap(const char* const words[], @@ -301,10 +258,6 @@ const char* const kUpperSegmentsList[] = {"url", "http", "https"}; std::unordered_set kUpperSegments = MakeWordsMap(kUpperSegmentsList, ABSL_ARRAYSIZE(kUpperSegmentsList)); -bool ascii_isnewline(char c) { - return c == '\n' || c == '\r'; -} - // Internal helper for name handing. // Do not expose this outside of helpers, stick to having functions for specific // cases (ClassName(), FieldName()), so there is always consistent suffix rules. @@ -377,7 +330,7 @@ std::string UnderscoresToCamelCase(const std::string& input, const char* const kReservedWordList[] = { // Note NSObject Methods: - // These are brought in from objectivec_nsobject_methods.h that is generated + // These are brought in from nsobject_methods.h that is generated // using method_dump.sh. See kNSObjectMethods below. // Objective C "keywords" that aren't in C @@ -534,34 +487,6 @@ bool IsSpecialNamePrefix(const std::string& name, return false; } -std::string GetZeroEnumNameForFlagType(const FlagType flag_type) { - switch(flag_type) { - case FLAGTYPE_DESCRIPTOR_INITIALIZATION: - return "GPBDescriptorInitializationFlag_None"; - case FLAGTYPE_EXTENSION: - return "GPBExtensionNone"; - case FLAGTYPE_FIELD: - return "GPBFieldNone"; - default: - GOOGLE_LOG(FATAL) << "Can't get here."; - return "0"; - } -} - -std::string GetEnumNameForFlagType(const FlagType flag_type) { - switch(flag_type) { - case FLAGTYPE_DESCRIPTOR_INITIALIZATION: - return "GPBDescriptorInitializationFlags"; - case FLAGTYPE_EXTENSION: - return "GPBExtensionOptions"; - case FLAGTYPE_FIELD: - return "GPBFieldFlags"; - default: - GOOGLE_LOG(FATAL) << "Can't get here."; - return std::string(); - } -} - void MaybeUnQuote(absl::string_view* input) { if ((input->length() >= 2) && ((*input->data() == '\'' || *input->data() == '"')) && @@ -573,20 +498,6 @@ void MaybeUnQuote(absl::string_view* input) { } // namespace -// Escape C++ trigraphs by escaping question marks to \? -std::string EscapeTrigraphs(absl::string_view to_escape) { - return absl::StrReplaceAll(to_escape, {{"?", "\\?"}}); -} - -void TrimWhitespace(absl::string_view* input) { - while (!input->empty() && absl::ascii_isspace(*input->data())) { - input->remove_prefix(1); - } - while (!input->empty() && absl::ascii_isspace((*input)[input->length() - 1])) { - input->remove_suffix(1); - } -} - bool IsRetainedName(const std::string& name) { // List of prefixes from // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html @@ -869,14 +780,6 @@ std::string OneofNameCapitalized(const OneofDescriptor* descriptor) { return result; } -std::string ObjCClass(const std::string& class_name) { - return std::string("GPBObjCClass(") + class_name + ")"; -} - -std::string ObjCClassDeclaration(const std::string& class_name) { - return std::string("GPBObjCClassDeclaration(") + class_name + ");"; -} - std::string UnCamelCaseFieldName(const std::string& name, const FieldDescriptor* field) { absl::string_view worker(name); if (absl::EndsWith(worker, "_p")) { @@ -911,369 +814,6 @@ std::string UnCamelCaseFieldName(const std::string& name, const FieldDescriptor* } } -std::string GetCapitalizedType(const FieldDescriptor* field) { - switch (field->type()) { - case FieldDescriptor::TYPE_INT32: - return "Int32"; - case FieldDescriptor::TYPE_UINT32: - return "UInt32"; - case FieldDescriptor::TYPE_SINT32: - return "SInt32"; - case FieldDescriptor::TYPE_FIXED32: - return "Fixed32"; - case FieldDescriptor::TYPE_SFIXED32: - return "SFixed32"; - case FieldDescriptor::TYPE_INT64: - return "Int64"; - case FieldDescriptor::TYPE_UINT64: - return "UInt64"; - case FieldDescriptor::TYPE_SINT64: - return "SInt64"; - case FieldDescriptor::TYPE_FIXED64: - return "Fixed64"; - case FieldDescriptor::TYPE_SFIXED64: - return "SFixed64"; - case FieldDescriptor::TYPE_FLOAT: - return "Float"; - case FieldDescriptor::TYPE_DOUBLE: - return "Double"; - case FieldDescriptor::TYPE_BOOL: - return "Bool"; - case FieldDescriptor::TYPE_STRING: - return "String"; - case FieldDescriptor::TYPE_BYTES: - return "Bytes"; - case FieldDescriptor::TYPE_ENUM: - return "Enum"; - case FieldDescriptor::TYPE_GROUP: - return "Group"; - case FieldDescriptor::TYPE_MESSAGE: - return "Message"; - } - - // Some compilers report reaching end of function even though all cases of - // the enum are handed in the switch. - GOOGLE_LOG(FATAL) << "Can't get here."; - return std::string(); -} - -ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type) { - switch (field_type) { - case FieldDescriptor::TYPE_INT32: - case FieldDescriptor::TYPE_SINT32: - case FieldDescriptor::TYPE_SFIXED32: - return OBJECTIVECTYPE_INT32; - - case FieldDescriptor::TYPE_UINT32: - case FieldDescriptor::TYPE_FIXED32: - return OBJECTIVECTYPE_UINT32; - - case FieldDescriptor::TYPE_INT64: - case FieldDescriptor::TYPE_SINT64: - case FieldDescriptor::TYPE_SFIXED64: - return OBJECTIVECTYPE_INT64; - - case FieldDescriptor::TYPE_UINT64: - case FieldDescriptor::TYPE_FIXED64: - return OBJECTIVECTYPE_UINT64; - - case FieldDescriptor::TYPE_FLOAT: - return OBJECTIVECTYPE_FLOAT; - - case FieldDescriptor::TYPE_DOUBLE: - return OBJECTIVECTYPE_DOUBLE; - - case FieldDescriptor::TYPE_BOOL: - return OBJECTIVECTYPE_BOOLEAN; - - case FieldDescriptor::TYPE_STRING: - return OBJECTIVECTYPE_STRING; - - case FieldDescriptor::TYPE_BYTES: - return OBJECTIVECTYPE_DATA; - - case FieldDescriptor::TYPE_ENUM: - return OBJECTIVECTYPE_ENUM; - - case FieldDescriptor::TYPE_GROUP: - case FieldDescriptor::TYPE_MESSAGE: - return OBJECTIVECTYPE_MESSAGE; - } - - // Some compilers report reaching end of function even though all cases of - // the enum are handed in the switch. - GOOGLE_LOG(FATAL) << "Can't get here."; - return OBJECTIVECTYPE_INT32; -} - -bool IsPrimitiveType(const FieldDescriptor* field) { - ObjectiveCType type = GetObjectiveCType(field); - switch (type) { - case OBJECTIVECTYPE_INT32: - case OBJECTIVECTYPE_UINT32: - case OBJECTIVECTYPE_INT64: - case OBJECTIVECTYPE_UINT64: - case OBJECTIVECTYPE_FLOAT: - case OBJECTIVECTYPE_DOUBLE: - case OBJECTIVECTYPE_BOOLEAN: - case OBJECTIVECTYPE_ENUM: - return true; - break; - default: - return false; - } -} - -bool IsReferenceType(const FieldDescriptor* field) { - return !IsPrimitiveType(field); -} - -static std::string HandleExtremeFloatingPoint(std::string val, - bool add_float_suffix) { - if (val == "nan") { - return "NAN"; - } else if (val == "inf") { - return "INFINITY"; - } else if (val == "-inf") { - return "-INFINITY"; - } else { - // float strings with ., e or E need to have f appended - if (add_float_suffix && (val.find('.') != std::string::npos || - val.find('e') != std::string::npos || - val.find('E') != std::string::npos)) { - val += "f"; - } - return val; - } -} - -std::string GPBGenericValueFieldName(const FieldDescriptor* field) { - // Returns the field within the GPBGenericValue union to use for the given - // field. - if (field->is_repeated()) { - return "valueMessage"; - } - switch (field->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: - return "valueInt32"; - case FieldDescriptor::CPPTYPE_UINT32: - return "valueUInt32"; - case FieldDescriptor::CPPTYPE_INT64: - return "valueInt64"; - case FieldDescriptor::CPPTYPE_UINT64: - return "valueUInt64"; - case FieldDescriptor::CPPTYPE_FLOAT: - return "valueFloat"; - case FieldDescriptor::CPPTYPE_DOUBLE: - return "valueDouble"; - case FieldDescriptor::CPPTYPE_BOOL: - return "valueBool"; - case FieldDescriptor::CPPTYPE_STRING: - if (field->type() == FieldDescriptor::TYPE_BYTES) { - return "valueData"; - } else { - return "valueString"; - } - case FieldDescriptor::CPPTYPE_ENUM: - return "valueEnum"; - case FieldDescriptor::CPPTYPE_MESSAGE: - return "valueMessage"; - } - - // Some compilers report reaching end of function even though all cases of - // the enum are handed in the switch. - GOOGLE_LOG(FATAL) << "Can't get here."; - return std::string(); -} - - -std::string DefaultValue(const FieldDescriptor* field) { - // Repeated fields don't have defaults. - if (field->is_repeated()) { - return "nil"; - } - - // Switch on cpp_type since we need to know which default_value_* method - // of FieldDescriptor to call. - switch (field->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: - // gcc and llvm reject the decimal form of kint32min and kint64min. - if (field->default_value_int32() == INT_MIN) { - return "-0x80000000"; - } - return absl::StrCat(field->default_value_int32()); - case FieldDescriptor::CPPTYPE_UINT32: - return absl::StrCat(field->default_value_uint32()) + "U"; - case FieldDescriptor::CPPTYPE_INT64: - // gcc and llvm reject the decimal form of kint32min and kint64min. - if (field->default_value_int64() == LLONG_MIN) { - return "-0x8000000000000000LL"; - } - return absl::StrCat(field->default_value_int64()) + "LL"; - case FieldDescriptor::CPPTYPE_UINT64: - return absl::StrCat(field->default_value_uint64()) + "ULL"; - case FieldDescriptor::CPPTYPE_DOUBLE: - return HandleExtremeFloatingPoint( - SimpleDtoa(field->default_value_double()), false); - case FieldDescriptor::CPPTYPE_FLOAT: - return HandleExtremeFloatingPoint( - SimpleFtoa(field->default_value_float()), true); - case FieldDescriptor::CPPTYPE_BOOL: - return field->default_value_bool() ? "YES" : "NO"; - case FieldDescriptor::CPPTYPE_STRING: { - const bool has_default_value = field->has_default_value(); - const std::string& default_string = field->default_value_string(); - if (!has_default_value || default_string.length() == 0) { - // If the field is defined as being the empty string, - // then we will just assign to nil, as the empty string is the - // default for both strings and data. - return "nil"; - } - if (field->type() == FieldDescriptor::TYPE_BYTES) { - // We want constant fields in our data structures so we can - // declare them as static. To achieve this we cheat and stuff - // a escaped c string (prefixed with a length) into the data - // field, and cast it to an (NSData*) so it will compile. - // The runtime library knows how to handle it. - - // Must convert to a standard byte order for packing length into - // a cstring. - uint32_t length = ghtonl(default_string.length()); - std::string bytes((const char*)&length, sizeof(length)); - bytes.append(default_string); - return "(NSData*)\"" + EscapeTrigraphs(absl::CEscape(bytes)) + "\""; - } else { - return "@\"" + EscapeTrigraphs(absl::CEscape(default_string)) + "\""; - } - } - case FieldDescriptor::CPPTYPE_ENUM: - return EnumValueName(field->default_value_enum()); - case FieldDescriptor::CPPTYPE_MESSAGE: - return "nil"; - } - - // Some compilers report reaching end of function even though all cases of - // the enum are handed in the switch. - GOOGLE_LOG(FATAL) << "Can't get here."; - return std::string(); -} - -bool HasNonZeroDefaultValue(const FieldDescriptor* field) { - // Repeated fields don't have defaults. - if (field->is_repeated()) { - return false; - } - - // As much as checking field->has_default_value() seems useful, it isn't - // because of enums. proto2 syntax allows the first item in an enum (the - // default) to be non zero. So checking field->has_default_value() would - // result in missing this non zero default. See MessageWithOneBasedEnum in - // objectivec/Tests/unittest_objc.proto for a test Message to confirm this. - - // Some proto file set the default to the zero value, so make sure the value - // isn't the zero case. - switch (field->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: - return field->default_value_int32() != 0; - case FieldDescriptor::CPPTYPE_UINT32: - return field->default_value_uint32() != 0U; - case FieldDescriptor::CPPTYPE_INT64: - return field->default_value_int64() != 0LL; - case FieldDescriptor::CPPTYPE_UINT64: - return field->default_value_uint64() != 0ULL; - case FieldDescriptor::CPPTYPE_DOUBLE: - return field->default_value_double() != 0.0; - case FieldDescriptor::CPPTYPE_FLOAT: - return field->default_value_float() != 0.0f; - case FieldDescriptor::CPPTYPE_BOOL: - return field->default_value_bool(); - case FieldDescriptor::CPPTYPE_STRING: { - const std::string& default_string = field->default_value_string(); - return default_string.length() != 0; - } - case FieldDescriptor::CPPTYPE_ENUM: - return field->default_value_enum()->number() != 0; - case FieldDescriptor::CPPTYPE_MESSAGE: - return false; - } - - // Some compilers report reaching end of function even though all cases of - // the enum are handed in the switch. - GOOGLE_LOG(FATAL) << "Can't get here."; - return false; -} - -std::string BuildFlagsString(const FlagType flag_type, - const std::vector& strings) { - if (strings.empty()) { - return GetZeroEnumNameForFlagType(flag_type); - } else if (strings.size() == 1) { - return strings[0]; - } - std::string string("(" + GetEnumNameForFlagType(flag_type) + ")("); - for (size_t i = 0; i != strings.size(); ++i) { - if (i > 0) { - string.append(" | "); - } - string.append(strings[i]); - } - string.append(")"); - return string; -} - -std::string BuildCommentsString(const SourceLocation& location, - bool prefer_single_line) { - const std::string& comments = location.leading_comments.empty() - ? location.trailing_comments - : location.leading_comments; - std::vector lines; - lines = absl::StrSplit(comments, "\n", absl::AllowEmpty()); - while (!lines.empty() && lines.back().empty()) { - lines.pop_back(); - } - // If there are no comments, just return an empty string. - if (lines.empty()) { - return ""; - } - - std::string prefix; - std::string suffix; - std::string final_comments; - std::string epilogue; - - bool add_leading_space = false; - - if (prefer_single_line && lines.size() == 1) { - prefix = "/** "; - suffix = " */\n"; - } else { - prefix = "* "; - suffix = "\n"; - final_comments += "/**\n"; - epilogue = " **/\n"; - add_leading_space = true; - } - - for (size_t i = 0; i < lines.size(); i++) { - std::string line = absl::StrReplaceAll( - absl::StripPrefix(lines[i], " "), - {// HeaderDoc and appledoc use '\' and '@' for markers; escape them. - {"\\", "\\\\"}, - {"@", "\\@"}, - // Decouple / from * to not have inline comments inside comments. - {"/*", "/\\*"}, - {"*/", "*\\/"}}); - line = prefix + line; - absl::StripAsciiWhitespace(&line); - // If not a one line, need to add the first space before *, as - // absl::StripAsciiWhitespace would have removed it. - line = (add_leading_space ? " " : "") + line; - final_comments += line + suffix; - } - final_comments += epilogue; - return final_comments; -} - // Making these a generator option for folks that don't use CocoaPods, but do // want to put the library in a framework is an interesting question. The // problem is it means changing sources shipped with the library to actually @@ -1308,25 +848,6 @@ bool IsProtobufLibraryBundledProtoFile(const FileDescriptor* file) { return false; } -bool ReadLine(absl::string_view* input, absl::string_view* line) { - for (int len = 0; len < input->size(); ++len) { - if (ascii_isnewline((*input)[len])) { - *line = absl::string_view(input->data(), len); - ++len; // advance over the newline - *input = absl::string_view(input->data() + len, input->size() - len); - return true; - } - } - return false; // Ran out of input with no newline. -} - -void RemoveComment(absl::string_view* input) { - int offset = input->find('#'); - if (offset != absl::string_view::npos) { - input->remove_suffix(input->length() - offset); - } -} - namespace { bool PackageToPrefixesCollector::ConsumeLine( @@ -1336,10 +857,8 @@ bool PackageToPrefixesCollector::ConsumeLine( *out_error = usage_ + " file line without equal sign: '" + absl::StrCat(line) + "'."; return false; } - absl::string_view package = line.substr(0, offset); - absl::string_view prefix = line.substr(offset + 1); - TrimWhitespace(&package); - TrimWhitespace(&prefix); + absl::string_view package = absl::StripAsciiWhitespace(line.substr(0, offset)); + absl::string_view prefix = absl::StripAsciiWhitespace(line.substr(offset + 1)); MaybeUnQuote(&prefix); // Don't really worry about error checking the package/prefix for // being valid. Assume the file is validated when it is created/edited. @@ -1506,6 +1025,24 @@ bool ValidateObjCClassPrefix( } // namespace +Options::Options() { + // While there are generator options, also support env variables to help with + // build systems where it isn't as easy to hook in for add the generation + // options when invoking protoc. + const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES"); + if (file_path) { + expected_prefixes_path = file_path; + } + const char* suppressions = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES_SUPPRESSIONS"); + if (suppressions) { + expected_prefixes_suppressions = + absl::StrSplit(suppressions, ";", absl::SkipEmpty()); + } + prefixes_must_be_registered = + BoolFromEnvVar("GPB_OBJC_PREFIXES_MUST_BE_REGISTERED", false); + require_prefixes = BoolFromEnvVar("GPB_OBJC_REQUIRE_PREFIXES", false); +} + bool ValidateObjCClassPrefixes(const std::vector& files, std::string* out_error) { // Options's ctor load from the environment. @@ -1554,541 +1091,6 @@ bool ValidateObjCClassPrefixes(const std::vector& files, return true; } -TextFormatDecodeData::TextFormatDecodeData() { } - -TextFormatDecodeData::~TextFormatDecodeData() { } - -void TextFormatDecodeData::AddString(int32_t key, - const std::string& input_for_decode, - const std::string& desired_output) { - for (std::vector::const_iterator i = entries_.begin(); - i != entries_.end(); ++i) { - if (i->first == key) { - std::cerr << "error: duplicate key (" << key - << ") making TextFormat data, input: \"" << input_for_decode - << "\", desired: \"" << desired_output << "\"." << std::endl; - std::cerr.flush(); - abort(); - } - } - - const std::string& data = TextFormatDecodeData::DecodeDataForString( - input_for_decode, desired_output); - entries_.push_back(DataEntry(key, data)); -} - -std::string TextFormatDecodeData::Data() const { - std::ostringstream data_stringstream; - - if (num_entries() > 0) { - io::OstreamOutputStream data_outputstream(&data_stringstream); - io::CodedOutputStream output_stream(&data_outputstream); - - output_stream.WriteVarint32(num_entries()); - for (std::vector::const_iterator i = entries_.begin(); - i != entries_.end(); ++i) { - output_stream.WriteVarint32(i->first); - output_stream.WriteString(i->second); - } - } - - data_stringstream.flush(); - return data_stringstream.str(); -} - -namespace { - -// Helper to build up the decode data for a string. -class DecodeDataBuilder { - public: - DecodeDataBuilder() { Reset(); } - - bool AddCharacter(const char desired, const char input); - void AddUnderscore() { - Push(); - need_underscore_ = true; - } - std::string Finish() { - Push(); - return decode_data_; - } - - private: - static constexpr uint8_t kAddUnderscore = 0x80; - - static constexpr uint8_t kOpAsIs = 0x00; - static constexpr uint8_t kOpFirstUpper = 0x40; - static constexpr uint8_t kOpFirstLower = 0x20; - static constexpr uint8_t kOpAllUpper = 0x60; - - static constexpr int kMaxSegmentLen = 0x1f; - - void AddChar(const char desired) { - ++segment_len_; - is_all_upper_ &= absl::ascii_isupper(desired); - } - - void Push() { - uint8_t op = (op_ | segment_len_); - if (need_underscore_) op |= kAddUnderscore; - if (op != 0) { - decode_data_ += (char)op; - } - Reset(); - } - - bool AddFirst(const char desired, const char input) { - if (desired == input) { - op_ = kOpAsIs; - } else if (desired == absl::ascii_toupper(input)) { - op_ = kOpFirstUpper; - } else if (desired == absl::ascii_tolower(input)) { - op_ = kOpFirstLower; - } else { - // Can't be transformed to match. - return false; - } - AddChar(desired); - return true; - } - - void Reset() { - need_underscore_ = false; - op_ = 0; - segment_len_ = 0; - is_all_upper_ = true; - } - - bool need_underscore_; - bool is_all_upper_; - uint8_t op_; - int segment_len_; - - std::string decode_data_; -}; - -bool DecodeDataBuilder::AddCharacter(const char desired, const char input) { - // If we've hit the max size, push to start a new segment. - if (segment_len_ == kMaxSegmentLen) { - Push(); - } - if (segment_len_ == 0) { - return AddFirst(desired, input); - } - - // Desired and input match... - if (desired == input) { - // If we aren't transforming it, or we're upper casing it and it is - // supposed to be uppercase; just add it to the segment. - if ((op_ != kOpAllUpper) || absl::ascii_isupper(desired)) { - AddChar(desired); - return true; - } - - // Add the current segment, and start the next one. - Push(); - return AddFirst(desired, input); - } - - // If we need to uppercase, and everything so far has been uppercase, - // promote op to AllUpper. - if ((desired == absl::ascii_toupper(input)) && is_all_upper_) { - op_ = kOpAllUpper; - AddChar(desired); - return true; - } - - // Give up, push and start a new segment. - Push(); - return AddFirst(desired, input); -} - -// If decode data can't be generated, a directive for the raw string -// is used instead. -std::string DirectDecodeString(const std::string& str) { - std::string result; - result += (char)'\0'; // Marker for full string. - result += str; - result += (char)'\0'; // End of string. - return result; -} - -} // namespace - -// static -std::string TextFormatDecodeData::DecodeDataForString( - const std::string& input_for_decode, const std::string& desired_output) { - if (input_for_decode.empty() || desired_output.empty()) { - std::cerr << "error: got empty string for making TextFormat data, input: \"" - << input_for_decode << "\", desired: \"" << desired_output << "\"." - << std::endl; - std::cerr.flush(); - abort(); - } - if ((input_for_decode.find('\0') != std::string::npos) || - (desired_output.find('\0') != std::string::npos)) { - std::cerr << "error: got a null char in a string for making TextFormat data," - << " input: \"" << absl::CEscape(input_for_decode) << "\", desired: \"" - << absl::CEscape(desired_output) << "\"." << std::endl; - std::cerr.flush(); - abort(); - } - - DecodeDataBuilder builder; - - // Walk the output building it from the input. - int x = 0; - for (int y = 0; y < desired_output.size(); y++) { - const char d = desired_output[y]; - if (d == '_') { - builder.AddUnderscore(); - continue; - } - - if (x >= input_for_decode.size()) { - // Out of input, no way to encode it, just return a full decode. - return DirectDecodeString(desired_output); - } - if (builder.AddCharacter(d, input_for_decode[x])) { - ++x; // Consumed one input - } else { - // Couldn't transform for the next character, just return a full decode. - return DirectDecodeString(desired_output); - } - } - - if (x != input_for_decode.size()) { - // Extra input (suffix from name sanitizing?), just return a full decode. - return DirectDecodeString(desired_output); - } - - // Add the end marker. - return builder.Finish() + (char)'\0'; -} - -namespace { - -class Parser { - public: - Parser(LineConsumer* line_consumer) - : line_consumer_(line_consumer), line_(0) {} - - // Feeds in some input, parse what it can, returning success/failure. Calling - // again after an error is undefined. - bool ParseChunk(absl::string_view chunk, std::string* out_error); - - // Should be called to finish parsing (after all input has been provided via - // successful calls to ParseChunk(), calling after a ParseChunk() failure is - // undefined). Returns success/failure. - bool Finish(std::string* out_error); - - int last_line() const { return line_; } - - private: - LineConsumer* line_consumer_; - int line_; - std::string leftover_; -}; - -bool Parser::ParseChunk(absl::string_view chunk, std::string* out_error) { - absl::string_view full_chunk; - if (!leftover_.empty()) { - leftover_ += std::string(chunk); - full_chunk = absl::string_view(leftover_); - } else { - full_chunk = chunk; - } - - absl::string_view line; - while (ReadLine(&full_chunk, &line)) { - ++line_; - RemoveComment(&line); - TrimWhitespace(&line); - if (!line.empty() && !line_consumer_->ConsumeLine(line, out_error)) { - if (out_error->empty()) { - *out_error = "ConsumeLine failed without setting an error."; - } - leftover_.clear(); - return false; - } - } - - if (full_chunk.empty()) { - leftover_.clear(); - } else { - leftover_ = std::string(full_chunk); - } - return true; -} - -bool Parser::Finish(std::string* out_error) { - // If there is still something to go, flush it with a newline. - if (!leftover_.empty() && !ParseChunk("\n", out_error)) { - return false; - } - // This really should never fail if ParseChunk succeeded, but check to be sure. - if (!leftover_.empty()) { - *out_error = "ParseSimple Internal error: finished with pending data."; - return false; - } - return true; -} - -std::string FullErrorString(const std::string& name, int line_num, const std::string& msg) { - return std::string("error: ") + name + " Line " + absl::StrCat(line_num) + ", " + msg; -} - -} // namespace - -LineConsumer::LineConsumer() {} - -LineConsumer::~LineConsumer() {} - -bool ParseSimpleFile(const std::string& path, LineConsumer* line_consumer, - std::string* out_error) { - int fd; - do { - fd = posix::open(path.c_str(), O_RDONLY); - } while (fd < 0 && errno == EINTR); - if (fd < 0) { - *out_error = std::string("error: Unable to open \"") + path + "\", " + - strerror(errno); - return false; - } - io::FileInputStream file_stream(fd); - file_stream.SetCloseOnDelete(true); - - return ParseSimpleStream(file_stream, path, line_consumer, out_error); -} - -bool ParseSimpleStream(io::ZeroCopyInputStream& input_stream, - const std::string& stream_name, - LineConsumer* line_consumer, - std::string* out_error) { - std::string local_error; - Parser parser(line_consumer); - const void* buf; - int buf_len; - while (input_stream.Next(&buf, &buf_len)) { - if (buf_len == 0) { - continue; - } - - if (!parser.ParseChunk(absl::string_view(static_cast(buf), buf_len), - &local_error)) { - *out_error = FullErrorString(stream_name, parser.last_line(), local_error); - return false; - } - } - if (!parser.Finish(&local_error)) { - *out_error = FullErrorString(stream_name, parser.last_line(), local_error); - return false; - } - return true; -} - -ImportWriter::ImportWriter( - const std::string& generate_for_named_framework, - const std::string& named_framework_to_proto_path_mappings_path, - const std::string& runtime_import_prefix, bool include_wkt_imports) - : generate_for_named_framework_(generate_for_named_framework), - named_framework_to_proto_path_mappings_path_( - named_framework_to_proto_path_mappings_path), - runtime_import_prefix_(runtime_import_prefix), - include_wkt_imports_(include_wkt_imports), - need_to_parse_mapping_file_(true) {} - -ImportWriter::~ImportWriter() {} - -void ImportWriter::AddFile(const FileDescriptor* file, - const std::string& header_extension) { - if (IsProtobufLibraryBundledProtoFile(file)) { - // The imports of the WKTs are only needed within the library itself, - // in other cases, they get skipped because the generated code already - // import GPBProtocolBuffers.h and hence proves them. - if (include_wkt_imports_) { - const std::string header_name = - "GPB" + FilePathBasename(file) + header_extension; - protobuf_imports_.push_back(header_name); - } - return; - } - - // Lazy parse any mappings. - if (need_to_parse_mapping_file_) { - ParseFrameworkMappings(); - } - - std::map::iterator proto_lookup = - proto_file_to_framework_name_.find(file->name()); - if (proto_lookup != proto_file_to_framework_name_.end()) { - other_framework_imports_.push_back( - proto_lookup->second + "/" + - FilePathBasename(file) + header_extension); - return; - } - - if (!generate_for_named_framework_.empty()) { - other_framework_imports_.push_back( - generate_for_named_framework_ + "/" + - FilePathBasename(file) + header_extension); - return; - } - - other_imports_.push_back(FilePath(file) + header_extension); -} - -void ImportWriter::Print(io::Printer* printer) const { - bool add_blank_line = false; - - if (!protobuf_imports_.empty()) { - PrintRuntimeImports(printer, protobuf_imports_, runtime_import_prefix_); - add_blank_line = true; - } - - if (!other_framework_imports_.empty()) { - if (add_blank_line) { - printer->Print("\n"); - } - - for (std::vector::const_iterator iter = - other_framework_imports_.begin(); - iter != other_framework_imports_.end(); ++iter) { - printer->Print( - "#import <$header$>\n", - "header", *iter); - } - - add_blank_line = true; - } - - if (!other_imports_.empty()) { - if (add_blank_line) { - printer->Print("\n"); - } - - for (std::vector::const_iterator iter = other_imports_.begin(); - iter != other_imports_.end(); ++iter) { - printer->Print( - "#import \"$header$\"\n", - "header", *iter); - } - } -} - -void ImportWriter::PrintRuntimeImports( - io::Printer* printer, const std::vector& header_to_import, - const std::string& runtime_import_prefix, bool default_cpp_symbol) { - // Given an override, use that. - if (!runtime_import_prefix.empty()) { - for (const auto& header : header_to_import) { - printer->Print( - " #import \"$import_prefix$/$header$\"\n", - "import_prefix", runtime_import_prefix, - "header", header); - } - return; - } - - const std::string framework_name(ProtobufLibraryFrameworkName); - const std::string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name)); - - if (default_cpp_symbol) { - printer->Print( - "// This CPP symbol can be defined to use imports that match up to the framework\n" - "// imports needed when using CocoaPods.\n" - "#if !defined($cpp_symbol$)\n" - " #define $cpp_symbol$ 0\n" - "#endif\n" - "\n", - "cpp_symbol", cpp_symbol); - } - - printer->Print( - "#if $cpp_symbol$\n", - "cpp_symbol", cpp_symbol); - for (const auto& header : header_to_import) { - printer->Print( - " #import <$framework_name$/$header$>\n", - "framework_name", framework_name, - "header", header); - } - printer->Print( - "#else\n"); - for (const auto& header : header_to_import) { - printer->Print( - " #import \"$header$\"\n", - "header", header); - } - printer->Print( - "#endif\n"); -} - -void ImportWriter::ParseFrameworkMappings() { - need_to_parse_mapping_file_ = false; - if (named_framework_to_proto_path_mappings_path_.empty()) { - return; // Nothing to do. - } - - ProtoFrameworkCollector collector(&proto_file_to_framework_name_); - std::string parse_error; - if (!ParseSimpleFile(named_framework_to_proto_path_mappings_path_, - &collector, &parse_error)) { - std::cerr << "error parsing " << named_framework_to_proto_path_mappings_path_ - << " : " << parse_error << std::endl; - std::cerr.flush(); - } -} - -bool ImportWriter::ProtoFrameworkCollector::ConsumeLine( - const absl::string_view& line, std::string* out_error) { - int offset = line.find(':'); - if (offset == absl::string_view::npos) { - *out_error = - std::string("Framework/proto file mapping line without colon sign: '") + - std::string(line) + "'."; - return false; - } - absl::string_view framework_name = line.substr(0, offset); - absl::string_view proto_file_list = line.substr(offset + 1); - TrimWhitespace(&framework_name); - - int start = 0; - while (start < proto_file_list.length()) { - offset = proto_file_list.find(',', start); - if (offset == absl::string_view::npos) { - offset = proto_file_list.length(); - } - - absl::string_view proto_file = proto_file_list.substr(start, offset - start); - TrimWhitespace(&proto_file); - if (!proto_file.empty()) { - std::map::iterator existing_entry = - map_->find(std::string(proto_file)); - if (existing_entry != map_->end()) { - std::cerr << "warning: duplicate proto file reference, replacing " - "framework entry for '" - << std::string(proto_file) << "' with '" << std::string(framework_name) - << "' (was '" << existing_entry->second << "')." << std::endl; - std::cerr.flush(); - } - - if (proto_file.find(' ') != absl::string_view::npos) { - std::cerr << "note: framework mapping file had a proto file with a " - "space in, hopefully that isn't a missing comma: '" - << std::string(proto_file) << "'" << std::endl; - std::cerr.flush(); - } - - (*map_)[std::string(proto_file)] = std::string(framework_name); - } - - start = offset + 1; - } - - return true; -} - } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/names.h b/src/google/protobuf/compiler/objectivec/names.h index e75738f323..e1b703c7bc 100644 --- a/src/google/protobuf/compiler/objectivec/names.h +++ b/src/google/protobuf/compiler/objectivec/names.h @@ -37,12 +37,10 @@ #include #include "google/protobuf/descriptor.h" -#include "google/protobuf/descriptor.pb.h" #include "google/protobuf/io/zero_copy_stream.h" -// clang-format off +// Must be included last #include "google/protobuf/port_def.inc" -// clang-format on namespace google { namespace protobuf { @@ -70,22 +68,6 @@ void PROTOC_EXPORT SetProtoPackagePrefixExceptionList( std::string PROTOC_EXPORT GetForcedPackagePrefix(); void PROTOC_EXPORT SetForcedPackagePrefix(const std::string& prefix); -// Generator Prefix Validation Options (see objectivec_generator.cc for a -// description of each): -struct Options { - Options(); - std::string expected_prefixes_path; - std::vector expected_prefixes_suppressions; - bool prefixes_must_be_registered; - bool require_prefixes; -}; - -// Escape C++ trigraphs by escaping question marks to "\?". -std::string PROTOC_EXPORT EscapeTrigraphs(absl::string_view to_escape); - -// Remove white space from either end of a absl::string_view. -void PROTOC_EXPORT TrimWhitespace(absl::string_view* input); - // Returns true if the name requires a ns_returns_not_retained attribute applied // to it. bool PROTOC_EXPORT IsRetainedName(const std::string& name); @@ -144,108 +126,10 @@ std::string PROTOC_EXPORT OneofEnumName(const OneofDescriptor* descriptor); std::string PROTOC_EXPORT OneofName(const OneofDescriptor* descriptor); std::string PROTOC_EXPORT OneofNameCapitalized(const OneofDescriptor* descriptor); -// Returns a symbol that can be used in C code to refer to an Objective C -// class without initializing the class. -std::string PROTOC_EXPORT ObjCClass(const std::string& class_name); - -// Declares an Objective C class without initializing the class so that it can -// be refrerred to by ObjCClass. -std::string PROTOC_EXPORT ObjCClassDeclaration(const std::string& class_name); - -inline bool HasPreservingUnknownEnumSemantics(const FileDescriptor* file) { - return file->syntax() == FileDescriptor::SYNTAX_PROTO3; -} - -inline bool IsMapEntryMessage(const Descriptor* descriptor) { - return descriptor->options().map_entry(); -} - // Reverse of the above. std::string PROTOC_EXPORT UnCamelCaseFieldName(const std::string& name, const FieldDescriptor* field); -enum ObjectiveCType { - OBJECTIVECTYPE_INT32, - OBJECTIVECTYPE_UINT32, - OBJECTIVECTYPE_INT64, - OBJECTIVECTYPE_UINT64, - OBJECTIVECTYPE_FLOAT, - OBJECTIVECTYPE_DOUBLE, - OBJECTIVECTYPE_BOOLEAN, - OBJECTIVECTYPE_STRING, - OBJECTIVECTYPE_DATA, - OBJECTIVECTYPE_ENUM, - OBJECTIVECTYPE_MESSAGE -}; - -enum FlagType { - FLAGTYPE_DESCRIPTOR_INITIALIZATION, - FLAGTYPE_EXTENSION, - FLAGTYPE_FIELD -}; - -template -std::string GetOptionalDeprecatedAttribute(const TDescriptor* descriptor, - const FileDescriptor* file = NULL, - bool preSpace = true, - bool postNewline = false) { - bool isDeprecated = descriptor->options().deprecated(); - // The file is only passed when checking Messages & Enums, so those types - // get tagged. At the moment, it doesn't seem to make sense to tag every - // field or enum value with when the file is deprecated. - bool isFileLevelDeprecation = false; - if (!isDeprecated && file) { - isFileLevelDeprecation = file->options().deprecated(); - isDeprecated = isFileLevelDeprecation; - } - if (isDeprecated) { - std::string message; - const FileDescriptor* sourceFile = descriptor->file(); - if (isFileLevelDeprecation) { - message = sourceFile->name() + " is deprecated."; - } else { - message = descriptor->full_name() + " is deprecated (see " + - sourceFile->name() + ")."; - } - - std::string result = std::string("GPB_DEPRECATED_MSG(\"") + message + "\")"; - if (preSpace) { - result.insert(0, " "); - } - if (postNewline) { - result.append("\n"); - } - return result; - } else { - return ""; - } -} - -std::string PROTOC_EXPORT GetCapitalizedType(const FieldDescriptor* field); - -ObjectiveCType PROTOC_EXPORT -GetObjectiveCType(FieldDescriptor::Type field_type); - -inline ObjectiveCType GetObjectiveCType(const FieldDescriptor* field) { - return GetObjectiveCType(field->type()); -} - -bool PROTOC_EXPORT IsPrimitiveType(const FieldDescriptor* field); -bool PROTOC_EXPORT IsReferenceType(const FieldDescriptor* field); - -std::string PROTOC_EXPORT -GPBGenericValueFieldName(const FieldDescriptor* field); -std::string PROTOC_EXPORT DefaultValue(const FieldDescriptor* field); -bool PROTOC_EXPORT HasNonZeroDefaultValue(const FieldDescriptor* field); - -std::string PROTOC_EXPORT -BuildFlagsString(const FlagType type, const std::vector& strings); - -// Builds HeaderDoc/appledoc style comments out of the comments in the .proto -// file. -std::string PROTOC_EXPORT BuildCommentsString(const SourceLocation& location, - bool prefer_single_line); - // The name the commonly used by the library when built as a framework. // This lines up to the name used in the CocoaPod. extern PROTOC_EXPORT const char* const ProtobufLibraryFrameworkName; @@ -254,10 +138,25 @@ extern PROTOC_EXPORT const char* const ProtobufLibraryFrameworkName; std::string PROTOC_EXPORT ProtobufFrameworkImportSymbol(const std::string& framework_name); +// --------------------------------------------------------------------------- + +// These aren't really "naming" related, but can be useful for something +// building on top of ObjC Protos to be able to share the knowledge/enforcement. + // Checks if the file is one of the proto's bundled with the library. bool PROTOC_EXPORT IsProtobufLibraryBundledProtoFile(const FileDescriptor* file); +// Generator Prefix Validation Options (see generator.cc for a +// description of each): +struct Options { + Options(); + std::string expected_prefixes_path; + std::vector expected_prefixes_suppressions; + bool prefixes_must_be_registered; + bool require_prefixes; +}; + // Checks the prefix for the given files and outputs any warnings as needed. If // there are flat out errors, then out_error is filled in with the first error // and the result is false. @@ -269,90 +168,6 @@ bool PROTOC_EXPORT ValidateObjCClassPrefixes( bool PROTOC_EXPORT ValidateObjCClassPrefixes( const std::vector& files, std::string* out_error); -// Generate decode data needed for ObjC's GPBDecodeTextFormatName() to transform -// the input into the expected output. -class PROTOC_EXPORT TextFormatDecodeData { - public: - TextFormatDecodeData(); - ~TextFormatDecodeData(); - - TextFormatDecodeData(const TextFormatDecodeData&) = delete; - TextFormatDecodeData& operator=(const TextFormatDecodeData&) = delete; - - void AddString(int32_t key, const std::string& input_for_decode, - const std::string& desired_output); - size_t num_entries() const { return entries_.size(); } - std::string Data() const; - - static std::string DecodeDataForString(const std::string& input_for_decode, - const std::string& desired_output); - - private: - typedef std::pair DataEntry; - std::vector entries_; -}; - -// Helper for parsing simple files. -class PROTOC_EXPORT LineConsumer { - public: - LineConsumer(); - virtual ~LineConsumer(); - virtual bool ConsumeLine(const absl::string_view& line, std::string* out_error) = 0; -}; - -bool PROTOC_EXPORT ParseSimpleFile(const std::string& path, - LineConsumer* line_consumer, - std::string* out_error); - -bool PROTOC_EXPORT ParseSimpleStream(io::ZeroCopyInputStream& input_stream, - const std::string& stream_name, - LineConsumer* line_consumer, - std::string* out_error); - -// Helper class for parsing framework import mappings and generating -// import statements. -class PROTOC_EXPORT ImportWriter { - public: - ImportWriter(const std::string& generate_for_named_framework, - const std::string& named_framework_to_proto_path_mappings_path, - const std::string& runtime_import_prefix, - bool include_wkt_imports); - ~ImportWriter(); - - void AddFile(const FileDescriptor* file, const std::string& header_extension); - void Print(io::Printer* printer) const; - - static void PrintRuntimeImports(io::Printer* printer, - const std::vector& header_to_import, - const std::string& runtime_import_prefix, - bool default_cpp_symbol = false); - - private: - class ProtoFrameworkCollector : public LineConsumer { - public: - ProtoFrameworkCollector(std::map* inout_proto_file_to_framework_name) - : map_(inout_proto_file_to_framework_name) {} - - virtual bool ConsumeLine(const absl::string_view& line, std::string* out_error) override; - - private: - std::map* map_; - }; - - void ParseFrameworkMappings(); - - const std::string generate_for_named_framework_; - const std::string named_framework_to_proto_path_mappings_path_; - const std::string runtime_import_prefix_; - const bool include_wkt_imports_; - std::map proto_file_to_framework_name_; - bool need_to_parse_mapping_file_; - - std::vector protobuf_imports_; - std::vector other_framework_imports_; - std::vector other_imports_; -}; - } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/names_unittest.cc b/src/google/protobuf/compiler/objectivec/names_unittest.cc new file mode 100644 index 0000000000..0aac79497c --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/names_unittest.cc @@ -0,0 +1,138 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/io/zero_copy_stream_impl_lite.h" + +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { +namespace { + +TEST(ObjCHelper, IsRetainedName) { + EXPECT_TRUE(IsRetainedName("new")); + EXPECT_TRUE(IsRetainedName("alloc")); + EXPECT_TRUE(IsRetainedName("copy")); + EXPECT_TRUE(IsRetainedName("mutableCopy")); + EXPECT_TRUE(IsRetainedName("newFoo")); + EXPECT_TRUE(IsRetainedName("allocFoo")); + EXPECT_TRUE(IsRetainedName("copyFoo")); + EXPECT_TRUE(IsRetainedName("mutableCopyFoo")); + EXPECT_TRUE(IsRetainedName("new_foo")); + EXPECT_TRUE(IsRetainedName("alloc_foo")); + EXPECT_TRUE(IsRetainedName("copy_foo")); + EXPECT_TRUE(IsRetainedName("mutableCopy_foo")); + + EXPECT_FALSE(IsRetainedName("")); + EXPECT_FALSE(IsRetainedName("ne")); + EXPECT_FALSE(IsRetainedName("all")); + EXPECT_FALSE(IsRetainedName("co")); + EXPECT_FALSE(IsRetainedName("mutable")); + EXPECT_FALSE(IsRetainedName("New")); + EXPECT_FALSE(IsRetainedName("Alloc")); + EXPECT_FALSE(IsRetainedName("Copy")); + EXPECT_FALSE(IsRetainedName("MutableCopy")); + EXPECT_FALSE(IsRetainedName("newer")); + EXPECT_FALSE(IsRetainedName("alloced")); + EXPECT_FALSE(IsRetainedName("copying")); + EXPECT_FALSE(IsRetainedName("mutableCopying")); + + EXPECT_FALSE(IsRetainedName("init")); + EXPECT_FALSE(IsRetainedName("Create")); + EXPECT_FALSE(IsRetainedName("Copy")); +} + +TEST(ObjCHelper, IsInitName) { + EXPECT_TRUE(IsInitName("init")); + EXPECT_TRUE(IsInitName("initFoo")); + EXPECT_TRUE(IsInitName("init_foo")); + + EXPECT_FALSE(IsInitName("")); + EXPECT_FALSE(IsInitName("in")); + EXPECT_FALSE(IsInitName("Init")); + EXPECT_FALSE(IsInitName("inIt")); + EXPECT_FALSE(IsInitName("initial")); + EXPECT_FALSE(IsInitName("initiAl")); + EXPECT_FALSE(IsInitName("fooInit")); + EXPECT_FALSE(IsInitName("foo_init")); + + EXPECT_FALSE(IsInitName("new")); + EXPECT_FALSE(IsInitName("alloc")); + EXPECT_FALSE(IsInitName("copy")); + EXPECT_FALSE(IsInitName("mutableCopy")); + EXPECT_FALSE(IsInitName("Create")); + EXPECT_FALSE(IsInitName("Copy")); +} + +TEST(ObjCHelper, IsCreateName) { + EXPECT_TRUE(IsCreateName("Create")); + EXPECT_TRUE(IsCreateName("Copy")); + EXPECT_TRUE(IsCreateName("CreateFoo")); + EXPECT_TRUE(IsCreateName("CopyFoo")); + EXPECT_TRUE(IsCreateName("Create_foo")); + EXPECT_TRUE(IsCreateName("Copy_foo")); + EXPECT_TRUE(IsCreateName("ReCreate")); + EXPECT_TRUE(IsCreateName("ReCopy")); + EXPECT_TRUE(IsCreateName("FOOCreate")); + EXPECT_TRUE(IsCreateName("FOOCopy")); + EXPECT_TRUE(IsCreateName("CreateWithCopy")); + + EXPECT_FALSE(IsCreateName("")); + EXPECT_FALSE(IsCreateName("Crea")); + EXPECT_FALSE(IsCreateName("Co")); + EXPECT_FALSE(IsCreateName("create")); + EXPECT_FALSE(IsCreateName("recreate")); + EXPECT_FALSE(IsCreateName("recopy")); + EXPECT_FALSE(IsCreateName("ReCreated")); + EXPECT_FALSE(IsCreateName("ReCopying")); + + EXPECT_FALSE(IsCreateName("init")); + EXPECT_FALSE(IsCreateName("new")); + EXPECT_FALSE(IsCreateName("alloc")); + EXPECT_FALSE(IsCreateName("copy")); + EXPECT_TRUE(IsCreateName("mutableCopy")); +} + +// TODO(thomasvl): Should probably add some unittests for all the special cases +// of name mangling (class name, field name, enum names). Rather than doing +// this with an ObjC test in the objectivec directory, we should be able to +// use src/google/protobuf/compiler/importer* (like other tests) to support a +// virtual file system to feed in protos, once we have the Descriptor tree, the +// tests could use the helper methods for generating names and validate the +// right things are happening. + +} // namespace +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/objectivec_nsobject_methods.h b/src/google/protobuf/compiler/objectivec/nsobject_methods.h similarity index 75% rename from src/google/protobuf/compiler/objectivec/objectivec_nsobject_methods.h rename to src/google/protobuf/compiler/objectivec/nsobject_methods.h index 163304665c..9c451b19a8 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_nsobject_methods.h +++ b/src/google/protobuf/compiler/objectivec/nsobject_methods.h @@ -1,3 +1,33 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + // NSObject methods // Autogenerated by method_dump.sh. Do not edit by hand. // Date: Thu Nov 1 14:12:16 PDT 2018 diff --git a/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc b/src/google/protobuf/compiler/objectivec/oneof.cc similarity index 96% rename from src/google/protobuf/compiler/objectivec/objectivec_oneof.cc rename to src/google/protobuf/compiler/objectivec/oneof.cc index 279928bba4..db4922f2d5 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc +++ b/src/google/protobuf/compiler/objectivec/oneof.cc @@ -28,13 +28,14 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "google/protobuf/compiler/objectivec/objectivec_oneof.h" +#include "google/protobuf/compiler/objectivec/oneof.h" #include #include #include "absl/strings/str_cat.h" -#include "google/protobuf/compiler/objectivec/objectivec_helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/compiler/objectivec/helpers.h" #include "google/protobuf/io/printer.h" namespace google { diff --git a/src/google/protobuf/compiler/objectivec/objectivec_oneof.h b/src/google/protobuf/compiler/objectivec/oneof.h similarity index 100% rename from src/google/protobuf/compiler/objectivec/objectivec_oneof.h rename to src/google/protobuf/compiler/objectivec/oneof.h diff --git a/src/google/protobuf/compiler/objectivec/objectivec_options.h b/src/google/protobuf/compiler/objectivec/options.h similarity index 97% rename from src/google/protobuf/compiler/objectivec/objectivec_options.h rename to src/google/protobuf/compiler/objectivec/options.h index 07b90b3d69..388d1cabfe 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_options.h +++ b/src/google/protobuf/compiler/objectivec/options.h @@ -38,7 +38,7 @@ namespace protobuf { namespace compiler { namespace objectivec { -// Generation options, documented within objectivec_generator.cc. +// Generation options, documented within generator.cc. struct GenerationOptions { std::string generate_for_named_framework; std::string named_framework_to_proto_path_mappings_path; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc b/src/google/protobuf/compiler/objectivec/primitive_field.cc similarity index 95% rename from src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc rename to src/google/protobuf/compiler/objectivec/primitive_field.cc index c9339a5aaa..739d1ce334 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc +++ b/src/google/protobuf/compiler/objectivec/primitive_field.cc @@ -28,13 +28,14 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "google/protobuf/compiler/objectivec/objectivec_primitive_field.h" +#include "google/protobuf/compiler/objectivec/primitive_field.h" #include #include #include "absl/strings/str_cat.h" -#include "google/protobuf/compiler/objectivec/objectivec_helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/compiler/objectivec/helpers.h" #include "google/protobuf/io/printer.h" namespace google { @@ -71,7 +72,7 @@ const char* PrimitiveTypeName(const FieldDescriptor* descriptor) { case OBJECTIVECTYPE_ENUM: return "int32_t"; case OBJECTIVECTYPE_MESSAGE: - return NULL; // Messages go through objectivec_message_field.cc|h. + return NULL; // Messages go through message_field.cc|h. } // Some compilers report reaching end of function even though all cases of @@ -104,7 +105,7 @@ const char* PrimitiveArrayTypeName(const FieldDescriptor* descriptor) { case OBJECTIVECTYPE_ENUM: return "Enum"; case OBJECTIVECTYPE_MESSAGE: - // Want NSArray (but goes through objectivec_message_field.cc|h). + // Want NSArray (but goes through message_field.cc|h). return ""; } diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h b/src/google/protobuf/compiler/objectivec/primitive_field.h similarity index 98% rename from src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h rename to src/google/protobuf/compiler/objectivec/primitive_field.h index 8948b48091..904cd65b4a 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h +++ b/src/google/protobuf/compiler/objectivec/primitive_field.h @@ -31,7 +31,7 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_PRIMITIVE_FIELD_H__ #define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_PRIMITIVE_FIELD_H__ -#include "google/protobuf/compiler/objectivec/objectivec_field.h" +#include "google/protobuf/compiler/objectivec/field.h" namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/objectivec/text_format_decode_data.cc b/src/google/protobuf/compiler/objectivec/text_format_decode_data.cc new file mode 100644 index 0000000000..9e5ef76af9 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/text_format_decode_data.cc @@ -0,0 +1,266 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/compiler/code_generator.h" +#include "absl/strings/ascii.h" +#include "absl/strings/escaping.h" +#include "absl/strings/str_split.h" +#include "absl/strings/str_replace.h" +#include "google/protobuf/compiler/objectivec/text_format_decode_data.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/io/coded_stream.h" +#include "google/protobuf/io/printer.h" +#include "google/protobuf/io/zero_copy_stream_impl.h" + +// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some +// error cases, so it seems to be ok to use as a back door for errors. + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +namespace { + +// Helper to build up the decode data for a string. +class DecodeDataBuilder { + public: + DecodeDataBuilder() { Reset(); } + + bool AddCharacter(const char desired, const char input); + void AddUnderscore() { + Push(); + need_underscore_ = true; + } + std::string Finish() { + Push(); + return decode_data_; + } + + private: + static constexpr uint8_t kAddUnderscore = 0x80; + + static constexpr uint8_t kOpAsIs = 0x00; + static constexpr uint8_t kOpFirstUpper = 0x40; + static constexpr uint8_t kOpFirstLower = 0x20; + static constexpr uint8_t kOpAllUpper = 0x60; + + static constexpr int kMaxSegmentLen = 0x1f; + + void AddChar(const char desired) { + ++segment_len_; + is_all_upper_ &= absl::ascii_isupper(desired); + } + + void Push() { + uint8_t op = (op_ | segment_len_); + if (need_underscore_) op |= kAddUnderscore; + if (op != 0) { + decode_data_ += (char)op; + } + Reset(); + } + + bool AddFirst(const char desired, const char input) { + if (desired == input) { + op_ = kOpAsIs; + } else if (desired == absl::ascii_toupper(input)) { + op_ = kOpFirstUpper; + } else if (desired == absl::ascii_tolower(input)) { + op_ = kOpFirstLower; + } else { + // Can't be transformed to match. + return false; + } + AddChar(desired); + return true; + } + + void Reset() { + need_underscore_ = false; + op_ = 0; + segment_len_ = 0; + is_all_upper_ = true; + } + + bool need_underscore_; + bool is_all_upper_; + uint8_t op_; + int segment_len_; + + std::string decode_data_; +}; + +bool DecodeDataBuilder::AddCharacter(const char desired, const char input) { + // If we've hit the max size, push to start a new segment. + if (segment_len_ == kMaxSegmentLen) { + Push(); + } + if (segment_len_ == 0) { + return AddFirst(desired, input); + } + + // Desired and input match... + if (desired == input) { + // If we aren't transforming it, or we're upper casing it and it is + // supposed to be uppercase; just add it to the segment. + if ((op_ != kOpAllUpper) || absl::ascii_isupper(desired)) { + AddChar(desired); + return true; + } + + // Add the current segment, and start the next one. + Push(); + return AddFirst(desired, input); + } + + // If we need to uppercase, and everything so far has been uppercase, + // promote op to AllUpper. + if ((desired == absl::ascii_toupper(input)) && is_all_upper_) { + op_ = kOpAllUpper; + AddChar(desired); + return true; + } + + // Give up, push and start a new segment. + Push(); + return AddFirst(desired, input); +} + +// If decode data can't be generated, a directive for the raw string +// is used instead. +std::string DirectDecodeString(const std::string& str) { + std::string result; + result += (char)'\0'; // Marker for full string. + result += str; + result += (char)'\0'; // End of string. + return result; +} + +} // namespace + +TextFormatDecodeData::TextFormatDecodeData() { } + +TextFormatDecodeData::~TextFormatDecodeData() { } + +void TextFormatDecodeData::AddString(int32_t key, + const std::string& input_for_decode, + const std::string& desired_output) { + for (std::vector::const_iterator i = entries_.begin(); + i != entries_.end(); ++i) { + if (i->first == key) { + std::cerr << "error: duplicate key (" << key + << ") making TextFormat data, input: \"" << input_for_decode + << "\", desired: \"" << desired_output << "\"." << std::endl; + std::cerr.flush(); + abort(); + } + } + + const std::string& data = TextFormatDecodeData::DecodeDataForString( + input_for_decode, desired_output); + entries_.push_back(DataEntry(key, data)); +} + +std::string TextFormatDecodeData::Data() const { + std::ostringstream data_stringstream; + + if (num_entries() > 0) { + io::OstreamOutputStream data_outputstream(&data_stringstream); + io::CodedOutputStream output_stream(&data_outputstream); + + output_stream.WriteVarint32(num_entries()); + for (std::vector::const_iterator i = entries_.begin(); + i != entries_.end(); ++i) { + output_stream.WriteVarint32(i->first); + output_stream.WriteString(i->second); + } + } + + data_stringstream.flush(); + return data_stringstream.str(); +} + +// static +std::string TextFormatDecodeData::DecodeDataForString( + const std::string& input_for_decode, const std::string& desired_output) { + if (input_for_decode.empty() || desired_output.empty()) { + std::cerr << "error: got empty string for making TextFormat data, input: \"" + << input_for_decode << "\", desired: \"" << desired_output << "\"." + << std::endl; + std::cerr.flush(); + abort(); + } + if ((input_for_decode.find('\0') != std::string::npos) || + (desired_output.find('\0') != std::string::npos)) { + std::cerr << "error: got a null char in a string for making TextFormat data," + << " input: \"" << absl::CEscape(input_for_decode) << "\", desired: \"" + << absl::CEscape(desired_output) << "\"." << std::endl; + std::cerr.flush(); + abort(); + } + + DecodeDataBuilder builder; + + // Walk the output building it from the input. + int x = 0; + for (int y = 0; y < desired_output.size(); y++) { + const char d = desired_output[y]; + if (d == '_') { + builder.AddUnderscore(); + continue; + } + + if (x >= input_for_decode.size()) { + // Out of input, no way to encode it, just return a full decode. + return DirectDecodeString(desired_output); + } + if (builder.AddCharacter(d, input_for_decode[x])) { + ++x; // Consumed one input + } else { + // Couldn't transform for the next character, just return a full decode. + return DirectDecodeString(desired_output); + } + } + + if (x != input_for_decode.size()) { + // Extra input (suffix from name sanitizing?), just return a full decode. + return DirectDecodeString(desired_output); + } + + // Add the end marker. + return builder.Finish() + (char)'\0'; +} + + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/text_format_decode_data.h b/src/google/protobuf/compiler/objectivec/text_format_decode_data.h new file mode 100644 index 0000000000..e7b63f65ff --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/text_format_decode_data.h @@ -0,0 +1,79 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_TEXT_FORMAT_DECODE_DATA_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_TEXT_FORMAT_DECODE_DATA_H__ + +#include +#include + +// Must be included last +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +// TODO(b/250947994): PROTOC_EXPORT is only used to allow the CMake build to +// find/link these in the unittest, this is not public api. + +// Generate decode data needed for ObjC's GPBDecodeTextFormatName() to transform +// the input into the expected output. +class PROTOC_EXPORT TextFormatDecodeData { + public: + TextFormatDecodeData(); + ~TextFormatDecodeData(); + + TextFormatDecodeData(const TextFormatDecodeData&) = delete; + TextFormatDecodeData& operator=(const TextFormatDecodeData&) = delete; + + void AddString(int32_t key, const std::string& input_for_decode, + const std::string& desired_output); + size_t num_entries() const { return entries_.size(); } + std::string Data() const; + + static std::string DecodeDataForString(const std::string& input_for_decode, + const std::string& desired_output); + + private: + typedef std::pair DataEntry; + std::vector entries_; +}; + + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include "google/protobuf/port_undef.inc" + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_TEXT_FORMAT_DECODE_DATA_H__ diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc b/src/google/protobuf/compiler/objectivec/text_format_decode_data_unittest.cc similarity index 57% rename from src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc rename to src/google/protobuf/compiler/objectivec/text_format_decode_data_unittest.cc index e6d0a7c613..ad1308ad9d 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc +++ b/src/google/protobuf/compiler/objectivec/text_format_decode_data_unittest.cc @@ -28,10 +28,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "google/protobuf/compiler/objectivec/objectivec_helpers.h" -#include "google/protobuf/io/zero_copy_stream_impl_lite.h" +#include "google/protobuf/compiler/objectivec/text_format_decode_data.h" + #include +// Must be included last +#include "google/protobuf/port_def.inc" + namespace google { namespace protobuf { namespace compiler { @@ -250,227 +253,10 @@ TEST(ObjCHelperDeathTest, TextFormatDecodeData_Failures) { } #endif // PROTOBUF_HAS_DEATH_TEST -class TestLineCollector : public LineConsumer { - public: - explicit TestLineCollector(std::vector* inout_lines, - const std::string* reject_line = nullptr, - bool skip_msg = false) - : lines_(inout_lines), reject_(reject_line), skip_msg_(skip_msg) {} - - bool ConsumeLine(const absl::string_view& line, std::string* out_error) override { - if (reject_ && *reject_ == line) { - if (!skip_msg_) { - *out_error = std::string("Rejected '") + *reject_ + "'"; - } - return false; - } - if (lines_) { - lines_->emplace_back(line); - } - return true; - } - - private: - std::vector* lines_; - const std::string* reject_; - bool skip_msg_; -}; - -const int kBlockSizes[] = {-1, 1, 2, 5, 64}; -const int kBlockSizeCount = ABSL_ARRAYSIZE(kBlockSizes); - -TEST(ObjCHelper, ParseSimple_BasicsSuccess) { - const std::vector>> tests = { - {"", {}}, - {"a", {"a"}}, - {"a c", {"a c"}}, - {" a c ", {"a c"}}, - {"\ta c ", {"a c"}}, - {"abc\n", {"abc"}}, - {"abc\nd f", {"abc", "d f"}}, - {"\n abc \n def \n\n", {"abc", "def"}}, - }; - - for (const auto& test : tests) { - for (int i = 0; i < kBlockSizeCount; i++) { - io::ArrayInputStream input(test.first.data(), test.first.size(), kBlockSizes[i]); - std::string err_str; - std::vector lines; - TestLineCollector collector(&lines); - EXPECT_TRUE(ParseSimpleStream(input, "dummy", &collector, &err_str)); - EXPECT_EQ(lines, test.second); - EXPECT_TRUE(err_str.empty()); - } - } -} - -TEST(ObjCHelper, ParseSimple_DropsComments) { - const std::vector>> tests = { - {"# nothing", {}}, - {"#", {}}, - {"##", {}}, - {"\n# nothing\n", {}}, - {"a # same line", {"a"}}, - {"a # same line\n", {"a"}}, - {"a\n# line\nc", {"a", "c"}}, - {"# n o t # h i n g #", {}}, - {"## n o # t h i n g #", {}}, - {"a# n o t # h i n g #", {"a"}}, - {"a\n## n o # t h i n g #", {"a"}}, - }; - - for (const auto& test : tests) { - for (int i = 0; i < kBlockSizeCount; i++) { - io::ArrayInputStream input(test.first.data(), test.first.size(), kBlockSizes[i]); - std::string err_str; - std::vector lines; - TestLineCollector collector(&lines); - EXPECT_TRUE(ParseSimpleStream(input, "dummy", &collector, &err_str)); - EXPECT_EQ(lines, test.second); - EXPECT_TRUE(err_str.empty()); - } - } -} - -TEST(ObjCHelper, ParseSimple_RejectLines) { - const std::vector> tests = { - std::make_tuple("a\nb\nc", "a", 1), - std::make_tuple("a\nb\nc", "b", 2), - std::make_tuple("a\nb\nc", "c", 3), - std::make_tuple("a\nb\nc\n", "c", 3), - }; - - for (const auto& test : tests) { - for (int i = 0; i < kBlockSizeCount; i++) { - io::ArrayInputStream input(std::get<0>(test).data(), std::get<0>(test).size(), - kBlockSizes[i]); - std::string err_str; - TestLineCollector collector(nullptr, &std::get<1>(test)); - EXPECT_FALSE(ParseSimpleStream(input, "dummy", &collector, &err_str)); - std::string expected_err = - absl::StrCat("error: dummy Line ", std::get<2>(test), ", Rejected '", std::get<1>(test), "'"); - EXPECT_EQ(err_str, expected_err); - } - } -} - -TEST(ObjCHelper, ParseSimple_RejectLinesNoMessage) { - const std::vector> tests = { - std::make_tuple("a\nb\nc", "a", 1), - std::make_tuple("a\nb\nc", "b", 2), - std::make_tuple("a\nb\nc", "c", 3), - std::make_tuple("a\nb\nc\n", "c", 3), - }; - - for (const auto& test : tests) { - for (int i = 0; i < kBlockSizeCount; i++) { - io::ArrayInputStream input(std::get<0>(test).data(), std::get<0>(test).size(), - kBlockSizes[i]); - std::string err_str; - TestLineCollector collector(nullptr, &std::get<1>(test), true /* skip msg */); - EXPECT_FALSE(ParseSimpleStream(input, "dummy", &collector, &err_str)); - std::string expected_err = - absl::StrCat("error: dummy Line ", std::get<2>(test), - ", ConsumeLine failed without setting an error."); - EXPECT_EQ(err_str, expected_err); - } - } -} - -TEST(ObjCHelper, IsRetainedName) { - EXPECT_TRUE(IsRetainedName("new")); - EXPECT_TRUE(IsRetainedName("alloc")); - EXPECT_TRUE(IsRetainedName("copy")); - EXPECT_TRUE(IsRetainedName("mutableCopy")); - EXPECT_TRUE(IsRetainedName("newFoo")); - EXPECT_TRUE(IsRetainedName("allocFoo")); - EXPECT_TRUE(IsRetainedName("copyFoo")); - EXPECT_TRUE(IsRetainedName("mutableCopyFoo")); - EXPECT_TRUE(IsRetainedName("new_foo")); - EXPECT_TRUE(IsRetainedName("alloc_foo")); - EXPECT_TRUE(IsRetainedName("copy_foo")); - EXPECT_TRUE(IsRetainedName("mutableCopy_foo")); - - EXPECT_FALSE(IsRetainedName("")); - EXPECT_FALSE(IsRetainedName("ne")); - EXPECT_FALSE(IsRetainedName("all")); - EXPECT_FALSE(IsRetainedName("co")); - EXPECT_FALSE(IsRetainedName("mutable")); - EXPECT_FALSE(IsRetainedName("New")); - EXPECT_FALSE(IsRetainedName("Alloc")); - EXPECT_FALSE(IsRetainedName("Copy")); - EXPECT_FALSE(IsRetainedName("MutableCopy")); - EXPECT_FALSE(IsRetainedName("newer")); - EXPECT_FALSE(IsRetainedName("alloced")); - EXPECT_FALSE(IsRetainedName("copying")); - EXPECT_FALSE(IsRetainedName("mutableCopying")); - - EXPECT_FALSE(IsRetainedName("init")); - EXPECT_FALSE(IsRetainedName("Create")); - EXPECT_FALSE(IsRetainedName("Copy")); -} - -TEST(ObjCHelper, IsInitName) { - EXPECT_TRUE(IsInitName("init")); - EXPECT_TRUE(IsInitName("initFoo")); - EXPECT_TRUE(IsInitName("init_foo")); - - EXPECT_FALSE(IsInitName("")); - EXPECT_FALSE(IsInitName("in")); - EXPECT_FALSE(IsInitName("Init")); - EXPECT_FALSE(IsInitName("inIt")); - EXPECT_FALSE(IsInitName("initial")); - EXPECT_FALSE(IsInitName("initiAl")); - EXPECT_FALSE(IsInitName("fooInit")); - EXPECT_FALSE(IsInitName("foo_init")); - - EXPECT_FALSE(IsInitName("new")); - EXPECT_FALSE(IsInitName("alloc")); - EXPECT_FALSE(IsInitName("copy")); - EXPECT_FALSE(IsInitName("mutableCopy")); - EXPECT_FALSE(IsInitName("Create")); - EXPECT_FALSE(IsInitName("Copy")); -} - -TEST(ObjCHelper, IsCreateName) { - EXPECT_TRUE(IsCreateName("Create")); - EXPECT_TRUE(IsCreateName("Copy")); - EXPECT_TRUE(IsCreateName("CreateFoo")); - EXPECT_TRUE(IsCreateName("CopyFoo")); - EXPECT_TRUE(IsCreateName("Create_foo")); - EXPECT_TRUE(IsCreateName("Copy_foo")); - EXPECT_TRUE(IsCreateName("ReCreate")); - EXPECT_TRUE(IsCreateName("ReCopy")); - EXPECT_TRUE(IsCreateName("FOOCreate")); - EXPECT_TRUE(IsCreateName("FOOCopy")); - EXPECT_TRUE(IsCreateName("CreateWithCopy")); - - EXPECT_FALSE(IsCreateName("")); - EXPECT_FALSE(IsCreateName("Crea")); - EXPECT_FALSE(IsCreateName("Co")); - EXPECT_FALSE(IsCreateName("create")); - EXPECT_FALSE(IsCreateName("recreate")); - EXPECT_FALSE(IsCreateName("recopy")); - EXPECT_FALSE(IsCreateName("ReCreated")); - EXPECT_FALSE(IsCreateName("ReCopying")); - - EXPECT_FALSE(IsCreateName("init")); - EXPECT_FALSE(IsCreateName("new")); - EXPECT_FALSE(IsCreateName("alloc")); - EXPECT_FALSE(IsCreateName("copy")); - EXPECT_TRUE(IsCreateName("mutableCopy")); -} - -// TODO(thomasvl): Should probably add some unittests for all the special cases -// of name mangling (class name, field name, enum names). Rather than doing -// this with an ObjC test in the objectivec directory, we should be able to -// use src/google/protobuf/compiler/importer* (like other tests) to support a -// virtual file system to feed in protos, once we have the Descriptor tree, the -// tests could use the helper methods for generating names and validate the -// right things are happening. - } // namespace } // namespace objectivec } // namespace compiler } // namespace protobuf } // namespace google + +#include "google/protobuf/port_undef.inc" diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc index dfba90790e..625281d9ac 100644 --- a/src/google/protobuf/compiler/parser.cc +++ b/src/google/protobuf/compiler/parser.cc @@ -1590,7 +1590,7 @@ bool Parser::ParseOption(Message* options, case io::Tokenizer::TYPE_FLOAT: { value_location.AddPath(UninterpretedOption::kDoubleValueFieldNumber); - double value; + double value = 0.0; DO(ConsumeNumber(&value, "Expected number.")); uninterpreted_option->set_double_value(is_negative ? -value : value); break; diff --git a/src/google/protobuf/compiler/php/php_generator.cc b/src/google/protobuf/compiler/php/php_generator.cc index 2903c3d432..b7b1d17071 100644 --- a/src/google/protobuf/compiler/php/php_generator.cc +++ b/src/google/protobuf/compiler/php/php_generator.cc @@ -33,7 +33,6 @@ #include #include "google/protobuf/compiler/code_generator.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/strings/ascii.h" #include "absl/strings/escaping.h" #include "absl/strings/str_replace.h" @@ -43,6 +42,8 @@ #include "google/protobuf/io/printer.h" #include "google/protobuf/io/zero_copy_stream.h" +#include "google/protobuf/stubs/strutil.h" // for StringReplace. + const std::string kDescriptorFile = "google/protobuf/descriptor.proto"; const std::string kEmptyFile = "google/protobuf/empty.proto"; const std::string kEmptyMetadataFile = "GPBMetadata/Google/Protobuf/GPBEmpty.php"; diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc index 87d4dda712..5560777a99 100644 --- a/src/google/protobuf/compiler/plugin.pb.cc +++ b/src/google/protobuf/compiler/plugin.pb.cc @@ -254,14 +254,17 @@ bool CodeGeneratorResponse_Feature_IsValid(int value) { return false; } } +#if (__cplusplus < 201703) && \ + (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) -#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::FEATURE_NONE; constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::FEATURE_PROTO3_OPTIONAL; constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::Feature_MIN; constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::Feature_MAX; constexpr int CodeGeneratorResponse::Feature_ARRAYSIZE; -#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) + +#endif // (__cplusplus < 201703) && + // (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) // =================================================================== class Version::_Internal { @@ -371,6 +374,7 @@ void Version::Clear() { } const char* Version::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -442,6 +446,7 @@ failure: uint8_t* Version::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.Version) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -484,6 +489,7 @@ uint8_t* Version::_InternalSerialize( } size_t Version::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.Version) size_t total_size = 0; @@ -529,6 +535,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Version::GetClassData() const void Version::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.Version) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -583,6 +590,7 @@ void Version::InternalSwap(Version* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata Version::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once, file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[0]); @@ -704,6 +712,7 @@ void CodeGeneratorRequest::Clear() { } const char* CodeGeneratorRequest::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -786,6 +795,7 @@ failure: uint8_t* CodeGeneratorRequest::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorRequest) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -835,6 +845,7 @@ uint8_t* CodeGeneratorRequest::_InternalSerialize( } size_t CodeGeneratorRequest::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorRequest) size_t total_size = 0; @@ -887,6 +898,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*CodeGeneratorRequest::GetClass void CodeGeneratorRequest::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorRequest) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -936,6 +948,7 @@ void CodeGeneratorRequest::InternalSwap(CodeGeneratorRequest* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata CodeGeneratorRequest::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once, file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[1]); @@ -1092,6 +1105,7 @@ void CodeGeneratorResponse_File::Clear() { } const char* CodeGeneratorResponse_File::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -1168,6 +1182,7 @@ failure: uint8_t* CodeGeneratorResponse_File::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorResponse.File) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -1219,6 +1234,7 @@ uint8_t* CodeGeneratorResponse_File::_InternalSerialize( } size_t CodeGeneratorResponse_File::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorResponse.File) size_t total_size = 0; @@ -1270,6 +1286,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*CodeGeneratorResponse_File::Ge void CodeGeneratorResponse_File::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse.File) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -1327,6 +1344,7 @@ void CodeGeneratorResponse_File::InternalSwap(CodeGeneratorResponse_File* other) } ::PROTOBUF_NAMESPACE_ID::Metadata CodeGeneratorResponse_File::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once, file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[2]); @@ -1428,6 +1446,7 @@ void CodeGeneratorResponse::Clear() { } const char* CodeGeneratorResponse::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -1494,6 +1513,7 @@ failure: uint8_t* CodeGeneratorResponse::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorResponse) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -1532,6 +1552,7 @@ uint8_t* CodeGeneratorResponse::_InternalSerialize( } size_t CodeGeneratorResponse::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorResponse) size_t total_size = 0; @@ -1574,6 +1595,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*CodeGeneratorResponse::GetClas void CodeGeneratorResponse::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -1619,6 +1641,7 @@ void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata CodeGeneratorResponse::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once, file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[3]); diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h index 5abaad9dd3..41403cf89f 100644 --- a/src/google/protobuf/compiler/plugin.pb.h +++ b/src/google/protobuf/compiler/plugin.pb.h @@ -15,7 +15,7 @@ #error "your headers." #endif // PROTOBUF_VERSION -#if 3021006 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021007 < PROTOBUF_MIN_PROTOC_VERSION #error "This file was generated by an older version of protoc which is" #error "incompatible with your Protocol Buffer headers. Please" #error "regenerate this file with a newer version of protoc." @@ -87,30 +87,31 @@ PROTOBUF_NAMESPACE_OPEN namespace compiler { enum CodeGeneratorResponse_Feature : int { CodeGeneratorResponse_Feature_FEATURE_NONE = 0, - CodeGeneratorResponse_Feature_FEATURE_PROTO3_OPTIONAL = 1 + CodeGeneratorResponse_Feature_FEATURE_PROTO3_OPTIONAL = 1, }; + PROTOC_EXPORT bool CodeGeneratorResponse_Feature_IsValid(int value); -constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse_Feature_Feature_MIN = CodeGeneratorResponse_Feature_FEATURE_NONE; -constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse_Feature_Feature_MAX = CodeGeneratorResponse_Feature_FEATURE_PROTO3_OPTIONAL; -constexpr int CodeGeneratorResponse_Feature_Feature_ARRAYSIZE = CodeGeneratorResponse_Feature_Feature_MAX + 1; - -PROTOC_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* CodeGeneratorResponse_Feature_descriptor(); -template -inline const std::string& CodeGeneratorResponse_Feature_Name(T enum_t_value) { - static_assert(::std::is_same::value || - ::std::is_integral::value, - "Incorrect type passed to function CodeGeneratorResponse_Feature_Name."); - return CodeGeneratorResponse_Feature_Name(static_cast(enum_t_value)); -} -template<> +constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse_Feature_Feature_MIN = static_cast(0); +constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse_Feature_Feature_MAX = static_cast(1); +constexpr int CodeGeneratorResponse_Feature_Feature_ARRAYSIZE = 1 + 1; +PROTOC_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* +CodeGeneratorResponse_Feature_descriptor(); +template +const std::string& CodeGeneratorResponse_Feature_Name(T value) { + static_assert(std::is_same::value || + std::is_integral::value, + "Incorrect type passed to Feature_Name()."); + return CodeGeneratorResponse_Feature_Name(static_cast(value)); +} +template <> inline const std::string& CodeGeneratorResponse_Feature_Name(CodeGeneratorResponse_Feature value) { - return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum - (static_cast(value)); + return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum( + static_cast(value)); } -inline bool CodeGeneratorResponse_Feature_Parse( - ::absl::string_view name, CodeGeneratorResponse_Feature* value) { +inline bool CodeGeneratorResponse_Feature_Parse(absl::string_view name, CodeGeneratorResponse_Feature* value) { return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum( - CodeGeneratorResponse_Feature_descriptor(), name, value); + CodeGeneratorResponse_Feature_descriptor(), name, value); } // =================================================================== @@ -908,33 +909,23 @@ class PROTOC_EXPORT CodeGeneratorResponse final : typedef CodeGeneratorResponse_File File; - typedef CodeGeneratorResponse_Feature Feature; - static constexpr Feature FEATURE_NONE = - CodeGeneratorResponse_Feature_FEATURE_NONE; - static constexpr Feature FEATURE_PROTO3_OPTIONAL = - CodeGeneratorResponse_Feature_FEATURE_PROTO3_OPTIONAL; + using Feature = CodeGeneratorResponse_Feature; + static constexpr Feature FEATURE_NONE = CodeGeneratorResponse_Feature_FEATURE_NONE; + static constexpr Feature FEATURE_PROTO3_OPTIONAL = CodeGeneratorResponse_Feature_FEATURE_PROTO3_OPTIONAL; static inline bool Feature_IsValid(int value) { return CodeGeneratorResponse_Feature_IsValid(value); } - static constexpr Feature Feature_MIN = - CodeGeneratorResponse_Feature_Feature_MIN; - static constexpr Feature Feature_MAX = - CodeGeneratorResponse_Feature_Feature_MAX; - static constexpr int Feature_ARRAYSIZE = - CodeGeneratorResponse_Feature_Feature_ARRAYSIZE; - static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* - Feature_descriptor() { + static constexpr Feature Feature_MIN = CodeGeneratorResponse_Feature_Feature_MIN; + static constexpr Feature Feature_MAX = CodeGeneratorResponse_Feature_Feature_MAX; + static constexpr int Feature_ARRAYSIZE = CodeGeneratorResponse_Feature_Feature_ARRAYSIZE; + static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Feature_descriptor() { return CodeGeneratorResponse_Feature_descriptor(); } - template - static inline const std::string& Feature_Name(T enum_t_value) { - static_assert(::std::is_same::value || - ::std::is_integral::value, - "Incorrect type passed to function Feature_Name."); - return CodeGeneratorResponse_Feature_Name(enum_t_value); + template + static inline const std::string& Feature_Name(T value) { + return CodeGeneratorResponse_Feature_Name(value); } - static inline bool Feature_Parse(::absl::string_view name, - Feature* value) { + static inline bool Feature_Parse(absl::string_view name, Feature* value) { return CodeGeneratorResponse_Feature_Parse(name, value); } @@ -1885,9 +1876,10 @@ PROTOBUF_NAMESPACE_CLOSE PROTOBUF_NAMESPACE_OPEN -template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_Feature> : ::std::true_type {}; template <> -inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_Feature>() { +struct is_proto_enum<::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_Feature> : std::true_type {}; +template <> +inline const EnumDescriptor* GetEnumDescriptor<::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_Feature>() { return ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_Feature_descriptor(); } diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index 54822bd8cc..a65ba74b47 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -2531,10 +2531,6 @@ void FileDescriptor::CopyTo(FileDescriptorProto* proto) const { for (int i = 0; i < extension_count(); i++) { extension(i)->CopyTo(proto->add_extension()); } - - if (&options() != &FileOptions::default_instance()) { - proto->mutable_options()->CopyFrom(options()); - } } void FileDescriptor::CopyHeadingTo(FileDescriptorProto* proto) const { @@ -2548,6 +2544,9 @@ void FileDescriptor::CopyHeadingTo(FileDescriptorProto* proto) const { ) { proto->set_syntax(SyntaxName(syntax())); } + if (&options() != &FileOptions::default_instance()) { + *proto->mutable_options() = options(); + } } void FileDescriptor::CopyJsonNameTo(FileDescriptorProto* proto) const { diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index 7d17e6b5eb..67b315a8cb 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -1292,8 +1292,9 @@ bool FieldDescriptorProto_Type_IsValid(int value) { return false; } } +#if (__cplusplus < 201703) && \ + (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) -#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_DOUBLE; constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FLOAT; constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_INT64; @@ -1315,7 +1316,9 @@ constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT64; constexpr FieldDescriptorProto_Type FieldDescriptorProto::Type_MIN; constexpr FieldDescriptorProto_Type FieldDescriptorProto::Type_MAX; constexpr int FieldDescriptorProto::Type_ARRAYSIZE; -#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) + +#endif // (__cplusplus < 201703) && + // (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldDescriptorProto_Label_descriptor() { ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto); return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[1]; @@ -1330,15 +1333,18 @@ bool FieldDescriptorProto_Label_IsValid(int value) { return false; } } +#if (__cplusplus < 201703) && \ + (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) -#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) constexpr FieldDescriptorProto_Label FieldDescriptorProto::LABEL_OPTIONAL; constexpr FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REQUIRED; constexpr FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REPEATED; constexpr FieldDescriptorProto_Label FieldDescriptorProto::Label_MIN; constexpr FieldDescriptorProto_Label FieldDescriptorProto::Label_MAX; constexpr int FieldDescriptorProto::Label_ARRAYSIZE; -#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) + +#endif // (__cplusplus < 201703) && + // (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FileOptions_OptimizeMode_descriptor() { ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto); return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[2]; @@ -1353,15 +1359,18 @@ bool FileOptions_OptimizeMode_IsValid(int value) { return false; } } +#if (__cplusplus < 201703) && \ + (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) -#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) constexpr FileOptions_OptimizeMode FileOptions::SPEED; constexpr FileOptions_OptimizeMode FileOptions::CODE_SIZE; constexpr FileOptions_OptimizeMode FileOptions::LITE_RUNTIME; constexpr FileOptions_OptimizeMode FileOptions::OptimizeMode_MIN; constexpr FileOptions_OptimizeMode FileOptions::OptimizeMode_MAX; constexpr int FileOptions::OptimizeMode_ARRAYSIZE; -#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) + +#endif // (__cplusplus < 201703) && + // (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldOptions_CType_descriptor() { ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto); return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[3]; @@ -1376,15 +1385,18 @@ bool FieldOptions_CType_IsValid(int value) { return false; } } +#if (__cplusplus < 201703) && \ + (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) -#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) constexpr FieldOptions_CType FieldOptions::STRING; constexpr FieldOptions_CType FieldOptions::CORD; constexpr FieldOptions_CType FieldOptions::STRING_PIECE; constexpr FieldOptions_CType FieldOptions::CType_MIN; constexpr FieldOptions_CType FieldOptions::CType_MAX; constexpr int FieldOptions::CType_ARRAYSIZE; -#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) + +#endif // (__cplusplus < 201703) && + // (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldOptions_JSType_descriptor() { ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto); return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[4]; @@ -1399,15 +1411,18 @@ bool FieldOptions_JSType_IsValid(int value) { return false; } } +#if (__cplusplus < 201703) && \ + (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) -#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) constexpr FieldOptions_JSType FieldOptions::JS_NORMAL; constexpr FieldOptions_JSType FieldOptions::JS_STRING; constexpr FieldOptions_JSType FieldOptions::JS_NUMBER; constexpr FieldOptions_JSType FieldOptions::JSType_MIN; constexpr FieldOptions_JSType FieldOptions::JSType_MAX; constexpr int FieldOptions::JSType_ARRAYSIZE; -#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) + +#endif // (__cplusplus < 201703) && + // (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* MethodOptions_IdempotencyLevel_descriptor() { ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto); return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[5]; @@ -1422,15 +1437,18 @@ bool MethodOptions_IdempotencyLevel_IsValid(int value) { return false; } } +#if (__cplusplus < 201703) && \ + (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) -#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) constexpr MethodOptions_IdempotencyLevel MethodOptions::IDEMPOTENCY_UNKNOWN; constexpr MethodOptions_IdempotencyLevel MethodOptions::NO_SIDE_EFFECTS; constexpr MethodOptions_IdempotencyLevel MethodOptions::IDEMPOTENT; constexpr MethodOptions_IdempotencyLevel MethodOptions::IdempotencyLevel_MIN; constexpr MethodOptions_IdempotencyLevel MethodOptions::IdempotencyLevel_MAX; constexpr int MethodOptions::IdempotencyLevel_ARRAYSIZE; -#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) + +#endif // (__cplusplus < 201703) && + // (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* GeneratedCodeInfo_Annotation_Semantic_descriptor() { ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto); return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[6]; @@ -1445,15 +1463,18 @@ bool GeneratedCodeInfo_Annotation_Semantic_IsValid(int value) { return false; } } +#if (__cplusplus < 201703) && \ + (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) -#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation::NONE; constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation::SET; constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation::ALIAS; constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation::Semantic_MIN; constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation::Semantic_MAX; constexpr int GeneratedCodeInfo_Annotation::Semantic_ARRAYSIZE; -#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) + +#endif // (__cplusplus < 201703) && + // (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) // =================================================================== class FileDescriptorSet::_Internal { @@ -1516,6 +1537,7 @@ void FileDescriptorSet::Clear() { } const char* FileDescriptorSet::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure while (!ctx->Done(&ptr)) { uint32_t tag; @@ -1559,6 +1581,7 @@ failure: uint8_t* FileDescriptorSet::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileDescriptorSet) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -1580,6 +1603,7 @@ uint8_t* FileDescriptorSet::_InternalSerialize( } size_t FileDescriptorSet::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileDescriptorSet) size_t total_size = 0; @@ -1607,6 +1631,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FileDescriptorSet::GetClassDat void FileDescriptorSet::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileDescriptorSet) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -1636,6 +1661,7 @@ void FileDescriptorSet::InternalSwap(FileDescriptorSet* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata FileDescriptorSet::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[0]); @@ -1855,6 +1881,7 @@ void FileDescriptorProto::Clear() { } const char* FileDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -2052,6 +2079,7 @@ failure: uint8_t* FileDescriptorProto::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileDescriptorProto) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -2174,6 +2202,7 @@ uint8_t* FileDescriptorProto::_InternalSerialize( } size_t FileDescriptorProto::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileDescriptorProto) size_t total_size = 0; @@ -2293,6 +2322,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FileDescriptorProto::GetClassD void FileDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileDescriptorProto) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -2391,6 +2421,7 @@ void FileDescriptorProto::InternalSwap(FileDescriptorProto* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata FileDescriptorProto::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[1]); @@ -2496,6 +2527,7 @@ void DescriptorProto_ExtensionRange::Clear() { } const char* DescriptorProto_ExtensionRange::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -2554,6 +2586,7 @@ failure: uint8_t* DescriptorProto_ExtensionRange::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto.ExtensionRange) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -2587,6 +2620,7 @@ uint8_t* DescriptorProto_ExtensionRange::_InternalSerialize( } size_t DescriptorProto_ExtensionRange::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto.ExtensionRange) size_t total_size = 0; @@ -2627,6 +2661,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*DescriptorProto_ExtensionRange void DescriptorProto_ExtensionRange::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto.ExtensionRange) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -2676,6 +2711,7 @@ void DescriptorProto_ExtensionRange::InternalSwap(DescriptorProto_ExtensionRange } ::PROTOBUF_NAMESPACE_ID::Metadata DescriptorProto_ExtensionRange::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[2]); @@ -2702,18 +2738,9 @@ DescriptorProto_ReservedRange::DescriptorProto_ReservedRange(::PROTOBUF_NAMESPAC // @@protoc_insertion_point(arena_constructor:google.protobuf.DescriptorProto.ReservedRange) } DescriptorProto_ReservedRange::DescriptorProto_ReservedRange(const DescriptorProto_ReservedRange& from) - : ::PROTOBUF_NAMESPACE_ID::Message() { - DescriptorProto_ReservedRange* const _this = this; (void)_this; - new (&_impl_) Impl_{ - decltype(_impl_._has_bits_){from._impl_._has_bits_} - , /*decltype(_impl_._cached_size_)*/{} - , decltype(_impl_.start_){} - , decltype(_impl_.end_){}}; - - _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); - ::memcpy(&_impl_.start_, &from._impl_.start_, - static_cast(reinterpret_cast(&_impl_.end_) - - reinterpret_cast(&_impl_.start_)) + sizeof(_impl_.end_)); + : ::PROTOBUF_NAMESPACE_ID::Message(), _impl_(from._impl_) { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>( + from._internal_metadata_); // @@protoc_insertion_point(copy_constructor:google.protobuf.DescriptorProto.ReservedRange) } @@ -2763,6 +2790,7 @@ void DescriptorProto_ReservedRange::Clear() { } const char* DescriptorProto_ReservedRange::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -2813,6 +2841,7 @@ failure: uint8_t* DescriptorProto_ReservedRange::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto.ReservedRange) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -2839,6 +2868,7 @@ uint8_t* DescriptorProto_ReservedRange::_InternalSerialize( } size_t DescriptorProto_ReservedRange::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto.ReservedRange) size_t total_size = 0; @@ -2872,6 +2902,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*DescriptorProto_ReservedRange: void DescriptorProto_ReservedRange::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto.ReservedRange) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -2914,6 +2945,7 @@ void DescriptorProto_ReservedRange::InternalSwap(DescriptorProto_ReservedRange* } ::PROTOBUF_NAMESPACE_ID::Metadata DescriptorProto_ReservedRange::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[3]); @@ -3056,6 +3088,7 @@ void DescriptorProto::Clear() { } const char* DescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -3216,6 +3249,7 @@ failure: uint8_t* DescriptorProto::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -3313,6 +3347,7 @@ uint8_t* DescriptorProto::_InternalSerialize( } size_t DescriptorProto::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto) size_t total_size = 0; @@ -3407,6 +3442,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*DescriptorProto::GetClassData( void DescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -3481,6 +3517,7 @@ void DescriptorProto::InternalSwap(DescriptorProto* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata DescriptorProto::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[4]); @@ -3552,6 +3589,7 @@ void ExtensionRangeOptions::Clear() { } const char* ExtensionRangeOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure while (!ctx->Done(&ptr)) { uint32_t tag; @@ -3600,6 +3638,7 @@ failure: uint8_t* ExtensionRangeOptions::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ExtensionRangeOptions) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -3625,6 +3664,7 @@ uint8_t* ExtensionRangeOptions::_InternalSerialize( } size_t ExtensionRangeOptions::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.ExtensionRangeOptions) size_t total_size = 0; @@ -3654,6 +3694,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*ExtensionRangeOptions::GetClas void ExtensionRangeOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ExtensionRangeOptions) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -3689,6 +3730,7 @@ void ExtensionRangeOptions::InternalSwap(ExtensionRangeOptions* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata ExtensionRangeOptions::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[5]); @@ -3921,6 +3963,7 @@ void FieldDescriptorProto::Clear() { } const char* FieldDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -4074,6 +4117,7 @@ failure: uint8_t* FieldDescriptorProto::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldDescriptorProto) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -4177,6 +4221,7 @@ uint8_t* FieldDescriptorProto::_InternalSerialize( } size_t FieldDescriptorProto::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldDescriptorProto) size_t total_size = 0; @@ -4271,6 +4316,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FieldDescriptorProto::GetClass void FieldDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldDescriptorProto) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -4371,6 +4417,7 @@ void FieldDescriptorProto::InternalSwap(FieldDescriptorProto* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata FieldDescriptorProto::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[6]); @@ -4481,6 +4528,7 @@ void OneofDescriptorProto::Clear() { } const char* OneofDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -4533,6 +4581,7 @@ failure: uint8_t* OneofDescriptorProto::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.OneofDescriptorProto) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -4564,6 +4613,7 @@ uint8_t* OneofDescriptorProto::_InternalSerialize( } size_t OneofDescriptorProto::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.OneofDescriptorProto) size_t total_size = 0; @@ -4601,6 +4651,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*OneofDescriptorProto::GetClass void OneofDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.OneofDescriptorProto) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -4647,6 +4698,7 @@ void OneofDescriptorProto::InternalSwap(OneofDescriptorProto* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata OneofDescriptorProto::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[7]); @@ -4673,18 +4725,9 @@ EnumDescriptorProto_EnumReservedRange::EnumDescriptorProto_EnumReservedRange(::P // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumDescriptorProto.EnumReservedRange) } EnumDescriptorProto_EnumReservedRange::EnumDescriptorProto_EnumReservedRange(const EnumDescriptorProto_EnumReservedRange& from) - : ::PROTOBUF_NAMESPACE_ID::Message() { - EnumDescriptorProto_EnumReservedRange* const _this = this; (void)_this; - new (&_impl_) Impl_{ - decltype(_impl_._has_bits_){from._impl_._has_bits_} - , /*decltype(_impl_._cached_size_)*/{} - , decltype(_impl_.start_){} - , decltype(_impl_.end_){}}; - - _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); - ::memcpy(&_impl_.start_, &from._impl_.start_, - static_cast(reinterpret_cast(&_impl_.end_) - - reinterpret_cast(&_impl_.start_)) + sizeof(_impl_.end_)); + : ::PROTOBUF_NAMESPACE_ID::Message(), _impl_(from._impl_) { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>( + from._internal_metadata_); // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumDescriptorProto.EnumReservedRange) } @@ -4734,6 +4777,7 @@ void EnumDescriptorProto_EnumReservedRange::Clear() { } const char* EnumDescriptorProto_EnumReservedRange::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -4784,6 +4828,7 @@ failure: uint8_t* EnumDescriptorProto_EnumReservedRange::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumDescriptorProto.EnumReservedRange) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -4810,6 +4855,7 @@ uint8_t* EnumDescriptorProto_EnumReservedRange::_InternalSerialize( } size_t EnumDescriptorProto_EnumReservedRange::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumDescriptorProto.EnumReservedRange) size_t total_size = 0; @@ -4843,6 +4889,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumDescriptorProto_EnumReserv void EnumDescriptorProto_EnumReservedRange::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumDescriptorProto.EnumReservedRange) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -4885,6 +4932,7 @@ void EnumDescriptorProto_EnumReservedRange::InternalSwap(EnumDescriptorProto_Enu } ::PROTOBUF_NAMESPACE_ID::Metadata EnumDescriptorProto_EnumReservedRange::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[8]); @@ -5007,6 +5055,7 @@ void EnumDescriptorProto::Clear() { } const char* EnumDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -5102,6 +5151,7 @@ failure: uint8_t* EnumDescriptorProto::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumDescriptorProto) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -5159,6 +5209,7 @@ uint8_t* EnumDescriptorProto::_InternalSerialize( } size_t EnumDescriptorProto::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumDescriptorProto) size_t total_size = 0; @@ -5218,6 +5269,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumDescriptorProto::GetClassD void EnumDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumDescriptorProto) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -5272,6 +5324,7 @@ void EnumDescriptorProto::InternalSwap(EnumDescriptorProto* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata EnumDescriptorProto::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[9]); @@ -5389,6 +5442,7 @@ void EnumValueDescriptorProto::Clear() { } const char* EnumValueDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -5450,6 +5504,7 @@ failure: uint8_t* EnumValueDescriptorProto::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValueDescriptorProto) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -5487,6 +5542,7 @@ uint8_t* EnumValueDescriptorProto::_InternalSerialize( } size_t EnumValueDescriptorProto::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValueDescriptorProto) size_t total_size = 0; @@ -5529,6 +5585,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumValueDescriptorProto::GetC void EnumValueDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValueDescriptorProto) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -5584,6 +5641,7 @@ void EnumValueDescriptorProto::InternalSwap(EnumValueDescriptorProto* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata EnumValueDescriptorProto::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[10]); @@ -5698,6 +5756,7 @@ void ServiceDescriptorProto::Clear() { } const char* ServiceDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -5763,6 +5822,7 @@ failure: uint8_t* ServiceDescriptorProto::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ServiceDescriptorProto) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -5802,6 +5862,7 @@ uint8_t* ServiceDescriptorProto::_InternalSerialize( } size_t ServiceDescriptorProto::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.ServiceDescriptorProto) size_t total_size = 0; @@ -5846,6 +5907,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*ServiceDescriptorProto::GetCla void ServiceDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ServiceDescriptorProto) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -5896,6 +5958,7 @@ void ServiceDescriptorProto::InternalSwap(ServiceDescriptorProto* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata ServiceDescriptorProto::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[11]); @@ -6064,6 +6127,7 @@ void MethodDescriptorProto::Clear() { } const char* MethodDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -6158,6 +6222,7 @@ failure: uint8_t* MethodDescriptorProto::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MethodDescriptorProto) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -6221,6 +6286,7 @@ uint8_t* MethodDescriptorProto::_InternalSerialize( } size_t MethodDescriptorProto::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.MethodDescriptorProto) size_t total_size = 0; @@ -6282,6 +6348,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*MethodDescriptorProto::GetClas void MethodDescriptorProto::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MethodDescriptorProto) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -6354,6 +6421,7 @@ void MethodDescriptorProto::InternalSwap(MethodDescriptorProto* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata MethodDescriptorProto::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[12]); @@ -6711,6 +6779,7 @@ void FileOptions::Clear() { } const char* FileOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -6975,6 +7044,7 @@ failure: uint8_t* FileOptions::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileOptions) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -7162,6 +7232,7 @@ uint8_t* FileOptions::_InternalSerialize( } size_t FileOptions::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileOptions) size_t total_size = 0; @@ -7319,6 +7390,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FileOptions::GetClassData() co void FileOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileOptions) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -7474,6 +7546,7 @@ void FileOptions::InternalSwap(FileOptions* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata FileOptions::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[13]); @@ -7577,6 +7650,7 @@ void MessageOptions::Clear() { } const char* MessageOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -7663,6 +7737,7 @@ failure: uint8_t* MessageOptions::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MessageOptions) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -7713,6 +7788,7 @@ uint8_t* MessageOptions::_InternalSerialize( } size_t MessageOptions::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.MessageOptions) size_t total_size = 0; @@ -7765,6 +7841,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*MessageOptions::GetClassData() void MessageOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MessageOptions) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -7823,6 +7900,7 @@ void MessageOptions::InternalSwap(MessageOptions* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata MessageOptions::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[14]); @@ -7944,6 +8022,7 @@ void FieldOptions::Clear() { } const char* FieldOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -8065,6 +8144,7 @@ failure: uint8_t* FieldOptions::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldOptions) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -8135,6 +8215,7 @@ uint8_t* FieldOptions::_InternalSerialize( } size_t FieldOptions::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldOptions) size_t total_size = 0; @@ -8204,6 +8285,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*FieldOptions::GetClassData() c void FieldOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldOptions) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -8271,6 +8353,7 @@ void FieldOptions::InternalSwap(FieldOptions* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata FieldOptions::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[15]); @@ -8342,6 +8425,7 @@ void OneofOptions::Clear() { } const char* OneofOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure while (!ctx->Done(&ptr)) { uint32_t tag; @@ -8390,6 +8474,7 @@ failure: uint8_t* OneofOptions::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.OneofOptions) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -8415,6 +8500,7 @@ uint8_t* OneofOptions::_InternalSerialize( } size_t OneofOptions::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.OneofOptions) size_t total_size = 0; @@ -8444,6 +8530,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*OneofOptions::GetClassData() c void OneofOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.OneofOptions) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -8479,6 +8566,7 @@ void OneofOptions::InternalSwap(OneofOptions* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata OneofOptions::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[16]); @@ -8572,6 +8660,7 @@ void EnumOptions::Clear() { } const char* EnumOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -8640,6 +8729,7 @@ failure: uint8_t* EnumOptions::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumOptions) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -8678,6 +8768,7 @@ uint8_t* EnumOptions::_InternalSerialize( } size_t EnumOptions::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumOptions) size_t total_size = 0; @@ -8720,6 +8811,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumOptions::GetClassData() co void EnumOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumOptions) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -8772,6 +8864,7 @@ void EnumOptions::InternalSwap(EnumOptions* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata EnumOptions::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[17]); @@ -8856,6 +8949,7 @@ void EnumValueOptions::Clear() { } const char* EnumValueOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -8915,6 +9009,7 @@ failure: uint8_t* EnumValueOptions::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValueOptions) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -8947,6 +9042,7 @@ uint8_t* EnumValueOptions::_InternalSerialize( } size_t EnumValueOptions::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValueOptions) size_t total_size = 0; @@ -8982,6 +9078,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*EnumValueOptions::GetClassData void EnumValueOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValueOptions) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -9022,6 +9119,7 @@ void EnumValueOptions::InternalSwap(EnumValueOptions* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata EnumValueOptions::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[18]); @@ -9106,6 +9204,7 @@ void ServiceOptions::Clear() { } const char* ServiceOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -9165,6 +9264,7 @@ failure: uint8_t* ServiceOptions::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ServiceOptions) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -9197,6 +9297,7 @@ uint8_t* ServiceOptions::_InternalSerialize( } size_t ServiceOptions::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.ServiceOptions) size_t total_size = 0; @@ -9232,6 +9333,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*ServiceOptions::GetClassData() void ServiceOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ServiceOptions) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -9272,6 +9374,7 @@ void ServiceOptions::InternalSwap(ServiceOptions* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata ServiceOptions::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[19]); @@ -9368,6 +9471,7 @@ void MethodOptions::Clear() { } const char* MethodOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -9440,6 +9544,7 @@ failure: uint8_t* MethodOptions::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MethodOptions) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -9479,6 +9584,7 @@ uint8_t* MethodOptions::_InternalSerialize( } size_t MethodOptions::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.MethodOptions) size_t total_size = 0; @@ -9522,6 +9628,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*MethodOptions::GetClassData() void MethodOptions::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MethodOptions) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -9574,6 +9681,7 @@ void MethodOptions::InternalSwap(MethodOptions* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata MethodOptions::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[20]); @@ -9674,6 +9782,7 @@ void UninterpretedOption_NamePart::Clear() { } const char* UninterpretedOption_NamePart::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -9727,6 +9836,7 @@ failure: uint8_t* UninterpretedOption_NamePart::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UninterpretedOption.NamePart) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -9775,6 +9885,7 @@ size_t UninterpretedOption_NamePart::RequiredFieldsByteSizeFallback() const { return total_size; } size_t UninterpretedOption_NamePart::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.UninterpretedOption.NamePart) size_t total_size = 0; @@ -9807,6 +9918,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*UninterpretedOption_NamePart:: void UninterpretedOption_NamePart::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UninterpretedOption.NamePart) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -9851,6 +9963,7 @@ void UninterpretedOption_NamePart::InternalSwap(UninterpretedOption_NamePart* ot } ::PROTOBUF_NAMESPACE_ID::Metadata UninterpretedOption_NamePart::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[21]); @@ -10012,6 +10125,7 @@ void UninterpretedOption::Clear() { } const char* UninterpretedOption::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -10117,6 +10231,7 @@ failure: uint8_t* UninterpretedOption::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UninterpretedOption) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -10183,6 +10298,7 @@ uint8_t* UninterpretedOption::_InternalSerialize( } size_t UninterpretedOption::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.UninterpretedOption) size_t total_size = 0; @@ -10249,6 +10365,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*UninterpretedOption::GetClassD void UninterpretedOption::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UninterpretedOption) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -10321,6 +10438,7 @@ void UninterpretedOption::InternalSwap(UninterpretedOption* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata UninterpretedOption::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[22]); @@ -10450,6 +10568,7 @@ void SourceCodeInfo_Location::Clear() { } const char* SourceCodeInfo_Location::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -10545,6 +10664,7 @@ failure: uint8_t* SourceCodeInfo_Location::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceCodeInfo.Location) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -10607,6 +10727,7 @@ uint8_t* SourceCodeInfo_Location::_InternalSerialize( } size_t SourceCodeInfo_Location::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceCodeInfo.Location) size_t total_size = 0; @@ -10678,6 +10799,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*SourceCodeInfo_Location::GetCl void SourceCodeInfo_Location::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceCodeInfo.Location) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -10729,6 +10851,7 @@ void SourceCodeInfo_Location::InternalSwap(SourceCodeInfo_Location* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata SourceCodeInfo_Location::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[23]); @@ -10795,6 +10918,7 @@ void SourceCodeInfo::Clear() { } const char* SourceCodeInfo::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure while (!ctx->Done(&ptr)) { uint32_t tag; @@ -10838,6 +10962,7 @@ failure: uint8_t* SourceCodeInfo::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceCodeInfo) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -10859,6 +10984,7 @@ uint8_t* SourceCodeInfo::_InternalSerialize( } size_t SourceCodeInfo::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceCodeInfo) size_t total_size = 0; @@ -10886,6 +11012,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*SourceCodeInfo::GetClassData() void SourceCodeInfo::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceCodeInfo) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -10913,6 +11040,7 @@ void SourceCodeInfo::InternalSwap(SourceCodeInfo* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata SourceCodeInfo::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[24]); @@ -11032,6 +11160,7 @@ void GeneratedCodeInfo_Annotation::Clear() { } const char* GeneratedCodeInfo_Annotation::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure _Internal::HasBits has_bits{}; while (!ctx->Done(&ptr)) { @@ -11118,6 +11247,7 @@ failure: uint8_t* GeneratedCodeInfo_Annotation::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.GeneratedCodeInfo.Annotation) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -11170,6 +11300,7 @@ uint8_t* GeneratedCodeInfo_Annotation::_InternalSerialize( } size_t GeneratedCodeInfo_Annotation::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.GeneratedCodeInfo.Annotation) size_t total_size = 0; @@ -11229,6 +11360,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GeneratedCodeInfo_Annotation:: void GeneratedCodeInfo_Annotation::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.GeneratedCodeInfo.Annotation) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -11285,6 +11417,7 @@ void GeneratedCodeInfo_Annotation::InternalSwap(GeneratedCodeInfo_Annotation* ot } ::PROTOBUF_NAMESPACE_ID::Metadata GeneratedCodeInfo_Annotation::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[25]); @@ -11351,6 +11484,7 @@ void GeneratedCodeInfo::Clear() { } const char* GeneratedCodeInfo::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) { + #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure while (!ctx->Done(&ptr)) { uint32_t tag; @@ -11394,6 +11528,7 @@ failure: uint8_t* GeneratedCodeInfo::_InternalSerialize( uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.GeneratedCodeInfo) uint32_t cached_has_bits = 0; (void) cached_has_bits; @@ -11415,6 +11550,7 @@ uint8_t* GeneratedCodeInfo::_InternalSerialize( } size_t GeneratedCodeInfo::ByteSizeLong() const { + // @@protoc_insertion_point(message_byte_size_start:google.protobuf.GeneratedCodeInfo) size_t total_size = 0; @@ -11442,6 +11578,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GeneratedCodeInfo::GetClassDat void GeneratedCodeInfo::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) { auto* const _this = static_cast(&to_msg); auto& from = static_cast(from_msg); + // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.GeneratedCodeInfo) GOOGLE_DCHECK_NE(&from, _this); uint32_t cached_has_bits = 0; @@ -11469,6 +11606,7 @@ void GeneratedCodeInfo::InternalSwap(GeneratedCodeInfo* other) { } ::PROTOBUF_NAMESPACE_ID::Metadata GeneratedCodeInfo::GetMetadata() const { + return ::_pbi::AssignDescriptors( &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[26]); diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index 6c664ab20b..46c3c13c34 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -15,7 +15,7 @@ #error "your headers." #endif // PROTOBUF_VERSION -#if 3021006 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021007 < PROTOBUF_MIN_PROTOC_VERSION #error "This file was generated by an older version of protoc which is" #error "incompatible with your Protocol Buffer headers. Please" #error "regenerate this file with a newer version of protoc." @@ -208,198 +208,205 @@ enum FieldDescriptorProto_Type : int { FieldDescriptorProto_Type_TYPE_SFIXED32 = 15, FieldDescriptorProto_Type_TYPE_SFIXED64 = 16, FieldDescriptorProto_Type_TYPE_SINT32 = 17, - FieldDescriptorProto_Type_TYPE_SINT64 = 18 + FieldDescriptorProto_Type_TYPE_SINT64 = 18, }; + PROTOBUF_EXPORT bool FieldDescriptorProto_Type_IsValid(int value); -constexpr FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MIN = FieldDescriptorProto_Type_TYPE_DOUBLE; -constexpr FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MAX = FieldDescriptorProto_Type_TYPE_SINT64; -constexpr int FieldDescriptorProto_Type_Type_ARRAYSIZE = FieldDescriptorProto_Type_Type_MAX + 1; - -PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldDescriptorProto_Type_descriptor(); -template -inline const std::string& FieldDescriptorProto_Type_Name(T enum_t_value) { - static_assert(::std::is_same::value || - ::std::is_integral::value, - "Incorrect type passed to function FieldDescriptorProto_Type_Name."); - return FieldDescriptorProto_Type_Name(static_cast(enum_t_value)); -} -template<> +constexpr FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MIN = static_cast(1); +constexpr FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MAX = static_cast(18); +constexpr int FieldDescriptorProto_Type_Type_ARRAYSIZE = 18 + 1; +PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* +FieldDescriptorProto_Type_descriptor(); +template +const std::string& FieldDescriptorProto_Type_Name(T value) { + static_assert(std::is_same::value || + std::is_integral::value, + "Incorrect type passed to Type_Name()."); + return FieldDescriptorProto_Type_Name(static_cast(value)); +} +template <> inline const std::string& FieldDescriptorProto_Type_Name(FieldDescriptorProto_Type value) { - return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum - (static_cast(value)); + return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum( + static_cast(value)); } -inline bool FieldDescriptorProto_Type_Parse( - ::absl::string_view name, FieldDescriptorProto_Type* value) { +inline bool FieldDescriptorProto_Type_Parse(absl::string_view name, FieldDescriptorProto_Type* value) { return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum( - FieldDescriptorProto_Type_descriptor(), name, value); + FieldDescriptorProto_Type_descriptor(), name, value); } enum FieldDescriptorProto_Label : int { FieldDescriptorProto_Label_LABEL_OPTIONAL = 1, FieldDescriptorProto_Label_LABEL_REQUIRED = 2, - FieldDescriptorProto_Label_LABEL_REPEATED = 3 + FieldDescriptorProto_Label_LABEL_REPEATED = 3, }; + PROTOBUF_EXPORT bool FieldDescriptorProto_Label_IsValid(int value); -constexpr FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MIN = FieldDescriptorProto_Label_LABEL_OPTIONAL; -constexpr FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MAX = FieldDescriptorProto_Label_LABEL_REPEATED; -constexpr int FieldDescriptorProto_Label_Label_ARRAYSIZE = FieldDescriptorProto_Label_Label_MAX + 1; - -PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldDescriptorProto_Label_descriptor(); -template -inline const std::string& FieldDescriptorProto_Label_Name(T enum_t_value) { - static_assert(::std::is_same::value || - ::std::is_integral::value, - "Incorrect type passed to function FieldDescriptorProto_Label_Name."); - return FieldDescriptorProto_Label_Name(static_cast(enum_t_value)); -} -template<> +constexpr FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MIN = static_cast(1); +constexpr FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MAX = static_cast(3); +constexpr int FieldDescriptorProto_Label_Label_ARRAYSIZE = 3 + 1; +PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* +FieldDescriptorProto_Label_descriptor(); +template +const std::string& FieldDescriptorProto_Label_Name(T value) { + static_assert(std::is_same::value || + std::is_integral::value, + "Incorrect type passed to Label_Name()."); + return FieldDescriptorProto_Label_Name(static_cast(value)); +} +template <> inline const std::string& FieldDescriptorProto_Label_Name(FieldDescriptorProto_Label value) { - return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum - (static_cast(value)); + return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum( + static_cast(value)); } -inline bool FieldDescriptorProto_Label_Parse( - ::absl::string_view name, FieldDescriptorProto_Label* value) { +inline bool FieldDescriptorProto_Label_Parse(absl::string_view name, FieldDescriptorProto_Label* value) { return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum( - FieldDescriptorProto_Label_descriptor(), name, value); + FieldDescriptorProto_Label_descriptor(), name, value); } enum FileOptions_OptimizeMode : int { FileOptions_OptimizeMode_SPEED = 1, FileOptions_OptimizeMode_CODE_SIZE = 2, - FileOptions_OptimizeMode_LITE_RUNTIME = 3 + FileOptions_OptimizeMode_LITE_RUNTIME = 3, }; + PROTOBUF_EXPORT bool FileOptions_OptimizeMode_IsValid(int value); -constexpr FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MIN = FileOptions_OptimizeMode_SPEED; -constexpr FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MAX = FileOptions_OptimizeMode_LITE_RUNTIME; -constexpr int FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE = FileOptions_OptimizeMode_OptimizeMode_MAX + 1; - -PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FileOptions_OptimizeMode_descriptor(); -template -inline const std::string& FileOptions_OptimizeMode_Name(T enum_t_value) { - static_assert(::std::is_same::value || - ::std::is_integral::value, - "Incorrect type passed to function FileOptions_OptimizeMode_Name."); - return FileOptions_OptimizeMode_Name(static_cast(enum_t_value)); -} -template<> +constexpr FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MIN = static_cast(1); +constexpr FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MAX = static_cast(3); +constexpr int FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE = 3 + 1; +PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* +FileOptions_OptimizeMode_descriptor(); +template +const std::string& FileOptions_OptimizeMode_Name(T value) { + static_assert(std::is_same::value || + std::is_integral::value, + "Incorrect type passed to OptimizeMode_Name()."); + return FileOptions_OptimizeMode_Name(static_cast(value)); +} +template <> inline const std::string& FileOptions_OptimizeMode_Name(FileOptions_OptimizeMode value) { - return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum - (static_cast(value)); + return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum( + static_cast(value)); } -inline bool FileOptions_OptimizeMode_Parse( - ::absl::string_view name, FileOptions_OptimizeMode* value) { +inline bool FileOptions_OptimizeMode_Parse(absl::string_view name, FileOptions_OptimizeMode* value) { return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum( - FileOptions_OptimizeMode_descriptor(), name, value); + FileOptions_OptimizeMode_descriptor(), name, value); } enum FieldOptions_CType : int { FieldOptions_CType_STRING = 0, FieldOptions_CType_CORD = 1, - FieldOptions_CType_STRING_PIECE = 2 + FieldOptions_CType_STRING_PIECE = 2, }; + PROTOBUF_EXPORT bool FieldOptions_CType_IsValid(int value); -constexpr FieldOptions_CType FieldOptions_CType_CType_MIN = FieldOptions_CType_STRING; -constexpr FieldOptions_CType FieldOptions_CType_CType_MAX = FieldOptions_CType_STRING_PIECE; -constexpr int FieldOptions_CType_CType_ARRAYSIZE = FieldOptions_CType_CType_MAX + 1; - -PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldOptions_CType_descriptor(); -template -inline const std::string& FieldOptions_CType_Name(T enum_t_value) { - static_assert(::std::is_same::value || - ::std::is_integral::value, - "Incorrect type passed to function FieldOptions_CType_Name."); - return FieldOptions_CType_Name(static_cast(enum_t_value)); -} -template<> +constexpr FieldOptions_CType FieldOptions_CType_CType_MIN = static_cast(0); +constexpr FieldOptions_CType FieldOptions_CType_CType_MAX = static_cast(2); +constexpr int FieldOptions_CType_CType_ARRAYSIZE = 2 + 1; +PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* +FieldOptions_CType_descriptor(); +template +const std::string& FieldOptions_CType_Name(T value) { + static_assert(std::is_same::value || + std::is_integral::value, + "Incorrect type passed to CType_Name()."); + return FieldOptions_CType_Name(static_cast(value)); +} +template <> inline const std::string& FieldOptions_CType_Name(FieldOptions_CType value) { - return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum - (static_cast(value)); + return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum( + static_cast(value)); } -inline bool FieldOptions_CType_Parse( - ::absl::string_view name, FieldOptions_CType* value) { +inline bool FieldOptions_CType_Parse(absl::string_view name, FieldOptions_CType* value) { return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum( - FieldOptions_CType_descriptor(), name, value); + FieldOptions_CType_descriptor(), name, value); } enum FieldOptions_JSType : int { FieldOptions_JSType_JS_NORMAL = 0, FieldOptions_JSType_JS_STRING = 1, - FieldOptions_JSType_JS_NUMBER = 2 + FieldOptions_JSType_JS_NUMBER = 2, }; + PROTOBUF_EXPORT bool FieldOptions_JSType_IsValid(int value); -constexpr FieldOptions_JSType FieldOptions_JSType_JSType_MIN = FieldOptions_JSType_JS_NORMAL; -constexpr FieldOptions_JSType FieldOptions_JSType_JSType_MAX = FieldOptions_JSType_JS_NUMBER; -constexpr int FieldOptions_JSType_JSType_ARRAYSIZE = FieldOptions_JSType_JSType_MAX + 1; - -PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldOptions_JSType_descriptor(); -template -inline const std::string& FieldOptions_JSType_Name(T enum_t_value) { - static_assert(::std::is_same::value || - ::std::is_integral::value, - "Incorrect type passed to function FieldOptions_JSType_Name."); - return FieldOptions_JSType_Name(static_cast(enum_t_value)); -} -template<> +constexpr FieldOptions_JSType FieldOptions_JSType_JSType_MIN = static_cast(0); +constexpr FieldOptions_JSType FieldOptions_JSType_JSType_MAX = static_cast(2); +constexpr int FieldOptions_JSType_JSType_ARRAYSIZE = 2 + 1; +PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* +FieldOptions_JSType_descriptor(); +template +const std::string& FieldOptions_JSType_Name(T value) { + static_assert(std::is_same::value || + std::is_integral::value, + "Incorrect type passed to JSType_Name()."); + return FieldOptions_JSType_Name(static_cast(value)); +} +template <> inline const std::string& FieldOptions_JSType_Name(FieldOptions_JSType value) { - return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum - (static_cast(value)); + return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum( + static_cast(value)); } -inline bool FieldOptions_JSType_Parse( - ::absl::string_view name, FieldOptions_JSType* value) { +inline bool FieldOptions_JSType_Parse(absl::string_view name, FieldOptions_JSType* value) { return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum( - FieldOptions_JSType_descriptor(), name, value); + FieldOptions_JSType_descriptor(), name, value); } enum MethodOptions_IdempotencyLevel : int { MethodOptions_IdempotencyLevel_IDEMPOTENCY_UNKNOWN = 0, MethodOptions_IdempotencyLevel_NO_SIDE_EFFECTS = 1, - MethodOptions_IdempotencyLevel_IDEMPOTENT = 2 + MethodOptions_IdempotencyLevel_IDEMPOTENT = 2, }; + PROTOBUF_EXPORT bool MethodOptions_IdempotencyLevel_IsValid(int value); -constexpr MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel_IdempotencyLevel_MIN = MethodOptions_IdempotencyLevel_IDEMPOTENCY_UNKNOWN; -constexpr MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX = MethodOptions_IdempotencyLevel_IDEMPOTENT; -constexpr int MethodOptions_IdempotencyLevel_IdempotencyLevel_ARRAYSIZE = MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX + 1; - -PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* MethodOptions_IdempotencyLevel_descriptor(); -template -inline const std::string& MethodOptions_IdempotencyLevel_Name(T enum_t_value) { - static_assert(::std::is_same::value || - ::std::is_integral::value, - "Incorrect type passed to function MethodOptions_IdempotencyLevel_Name."); - return MethodOptions_IdempotencyLevel_Name(static_cast(enum_t_value)); -} -template<> +constexpr MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel_IdempotencyLevel_MIN = static_cast(0); +constexpr MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX = static_cast(2); +constexpr int MethodOptions_IdempotencyLevel_IdempotencyLevel_ARRAYSIZE = 2 + 1; +PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* +MethodOptions_IdempotencyLevel_descriptor(); +template +const std::string& MethodOptions_IdempotencyLevel_Name(T value) { + static_assert(std::is_same::value || + std::is_integral::value, + "Incorrect type passed to IdempotencyLevel_Name()."); + return MethodOptions_IdempotencyLevel_Name(static_cast(value)); +} +template <> inline const std::string& MethodOptions_IdempotencyLevel_Name(MethodOptions_IdempotencyLevel value) { - return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum - (static_cast(value)); + return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum( + static_cast(value)); } -inline bool MethodOptions_IdempotencyLevel_Parse( - ::absl::string_view name, MethodOptions_IdempotencyLevel* value) { +inline bool MethodOptions_IdempotencyLevel_Parse(absl::string_view name, MethodOptions_IdempotencyLevel* value) { return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum( - MethodOptions_IdempotencyLevel_descriptor(), name, value); + MethodOptions_IdempotencyLevel_descriptor(), name, value); } enum GeneratedCodeInfo_Annotation_Semantic : int { GeneratedCodeInfo_Annotation_Semantic_NONE = 0, GeneratedCodeInfo_Annotation_Semantic_SET = 1, - GeneratedCodeInfo_Annotation_Semantic_ALIAS = 2 + GeneratedCodeInfo_Annotation_Semantic_ALIAS = 2, }; + PROTOBUF_EXPORT bool GeneratedCodeInfo_Annotation_Semantic_IsValid(int value); -constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation_Semantic_Semantic_MIN = GeneratedCodeInfo_Annotation_Semantic_NONE; -constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation_Semantic_Semantic_MAX = GeneratedCodeInfo_Annotation_Semantic_ALIAS; -constexpr int GeneratedCodeInfo_Annotation_Semantic_Semantic_ARRAYSIZE = GeneratedCodeInfo_Annotation_Semantic_Semantic_MAX + 1; - -PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* GeneratedCodeInfo_Annotation_Semantic_descriptor(); -template -inline const std::string& GeneratedCodeInfo_Annotation_Semantic_Name(T enum_t_value) { - static_assert(::std::is_same::value || - ::std::is_integral::value, - "Incorrect type passed to function GeneratedCodeInfo_Annotation_Semantic_Name."); - return GeneratedCodeInfo_Annotation_Semantic_Name(static_cast(enum_t_value)); -} -template<> +constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation_Semantic_Semantic_MIN = static_cast(0); +constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation_Semantic_Semantic_MAX = static_cast(2); +constexpr int GeneratedCodeInfo_Annotation_Semantic_Semantic_ARRAYSIZE = 2 + 1; +PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* +GeneratedCodeInfo_Annotation_Semantic_descriptor(); +template +const std::string& GeneratedCodeInfo_Annotation_Semantic_Name(T value) { + static_assert(std::is_same::value || + std::is_integral::value, + "Incorrect type passed to Semantic_Name()."); + return GeneratedCodeInfo_Annotation_Semantic_Name(static_cast(value)); +} +template <> inline const std::string& GeneratedCodeInfo_Annotation_Semantic_Name(GeneratedCodeInfo_Annotation_Semantic value) { - return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum - (static_cast(value)); + return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum( + static_cast(value)); } -inline bool GeneratedCodeInfo_Annotation_Semantic_Parse( - ::absl::string_view name, GeneratedCodeInfo_Annotation_Semantic* value) { +inline bool GeneratedCodeInfo_Annotation_Semantic_Parse(absl::string_view name, GeneratedCodeInfo_Annotation_Semantic* value) { return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum( - GeneratedCodeInfo_Annotation_Semantic_descriptor(), name, value); + GeneratedCodeInfo_Annotation_Semantic_descriptor(), name, value); } // =================================================================== @@ -2189,97 +2196,60 @@ class PROTOBUF_EXPORT FieldDescriptorProto final : // nested types ---------------------------------------------------- - typedef FieldDescriptorProto_Type Type; - static constexpr Type TYPE_DOUBLE = - FieldDescriptorProto_Type_TYPE_DOUBLE; - static constexpr Type TYPE_FLOAT = - FieldDescriptorProto_Type_TYPE_FLOAT; - static constexpr Type TYPE_INT64 = - FieldDescriptorProto_Type_TYPE_INT64; - static constexpr Type TYPE_UINT64 = - FieldDescriptorProto_Type_TYPE_UINT64; - static constexpr Type TYPE_INT32 = - FieldDescriptorProto_Type_TYPE_INT32; - static constexpr Type TYPE_FIXED64 = - FieldDescriptorProto_Type_TYPE_FIXED64; - static constexpr Type TYPE_FIXED32 = - FieldDescriptorProto_Type_TYPE_FIXED32; - static constexpr Type TYPE_BOOL = - FieldDescriptorProto_Type_TYPE_BOOL; - static constexpr Type TYPE_STRING = - FieldDescriptorProto_Type_TYPE_STRING; - static constexpr Type TYPE_GROUP = - FieldDescriptorProto_Type_TYPE_GROUP; - static constexpr Type TYPE_MESSAGE = - FieldDescriptorProto_Type_TYPE_MESSAGE; - static constexpr Type TYPE_BYTES = - FieldDescriptorProto_Type_TYPE_BYTES; - static constexpr Type TYPE_UINT32 = - FieldDescriptorProto_Type_TYPE_UINT32; - static constexpr Type TYPE_ENUM = - FieldDescriptorProto_Type_TYPE_ENUM; - static constexpr Type TYPE_SFIXED32 = - FieldDescriptorProto_Type_TYPE_SFIXED32; - static constexpr Type TYPE_SFIXED64 = - FieldDescriptorProto_Type_TYPE_SFIXED64; - static constexpr Type TYPE_SINT32 = - FieldDescriptorProto_Type_TYPE_SINT32; - static constexpr Type TYPE_SINT64 = - FieldDescriptorProto_Type_TYPE_SINT64; + using Type = FieldDescriptorProto_Type; + static constexpr Type TYPE_DOUBLE = FieldDescriptorProto_Type_TYPE_DOUBLE; + static constexpr Type TYPE_FLOAT = FieldDescriptorProto_Type_TYPE_FLOAT; + static constexpr Type TYPE_INT64 = FieldDescriptorProto_Type_TYPE_INT64; + static constexpr Type TYPE_UINT64 = FieldDescriptorProto_Type_TYPE_UINT64; + static constexpr Type TYPE_INT32 = FieldDescriptorProto_Type_TYPE_INT32; + static constexpr Type TYPE_FIXED64 = FieldDescriptorProto_Type_TYPE_FIXED64; + static constexpr Type TYPE_FIXED32 = FieldDescriptorProto_Type_TYPE_FIXED32; + static constexpr Type TYPE_BOOL = FieldDescriptorProto_Type_TYPE_BOOL; + static constexpr Type TYPE_STRING = FieldDescriptorProto_Type_TYPE_STRING; + static constexpr Type TYPE_GROUP = FieldDescriptorProto_Type_TYPE_GROUP; + static constexpr Type TYPE_MESSAGE = FieldDescriptorProto_Type_TYPE_MESSAGE; + static constexpr Type TYPE_BYTES = FieldDescriptorProto_Type_TYPE_BYTES; + static constexpr Type TYPE_UINT32 = FieldDescriptorProto_Type_TYPE_UINT32; + static constexpr Type TYPE_ENUM = FieldDescriptorProto_Type_TYPE_ENUM; + static constexpr Type TYPE_SFIXED32 = FieldDescriptorProto_Type_TYPE_SFIXED32; + static constexpr Type TYPE_SFIXED64 = FieldDescriptorProto_Type_TYPE_SFIXED64; + static constexpr Type TYPE_SINT32 = FieldDescriptorProto_Type_TYPE_SINT32; + static constexpr Type TYPE_SINT64 = FieldDescriptorProto_Type_TYPE_SINT64; static inline bool Type_IsValid(int value) { return FieldDescriptorProto_Type_IsValid(value); } - static constexpr Type Type_MIN = - FieldDescriptorProto_Type_Type_MIN; - static constexpr Type Type_MAX = - FieldDescriptorProto_Type_Type_MAX; - static constexpr int Type_ARRAYSIZE = - FieldDescriptorProto_Type_Type_ARRAYSIZE; - static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* - Type_descriptor() { + static constexpr Type Type_MIN = FieldDescriptorProto_Type_Type_MIN; + static constexpr Type Type_MAX = FieldDescriptorProto_Type_Type_MAX; + static constexpr int Type_ARRAYSIZE = FieldDescriptorProto_Type_Type_ARRAYSIZE; + static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Type_descriptor() { return FieldDescriptorProto_Type_descriptor(); } - template - static inline const std::string& Type_Name(T enum_t_value) { - static_assert(::std::is_same::value || - ::std::is_integral::value, - "Incorrect type passed to function Type_Name."); - return FieldDescriptorProto_Type_Name(enum_t_value); + template + static inline const std::string& Type_Name(T value) { + return FieldDescriptorProto_Type_Name(value); } - static inline bool Type_Parse(::absl::string_view name, - Type* value) { + static inline bool Type_Parse(absl::string_view name, Type* value) { return FieldDescriptorProto_Type_Parse(name, value); } - typedef FieldDescriptorProto_Label Label; - static constexpr Label LABEL_OPTIONAL = - FieldDescriptorProto_Label_LABEL_OPTIONAL; - static constexpr Label LABEL_REQUIRED = - FieldDescriptorProto_Label_LABEL_REQUIRED; - static constexpr Label LABEL_REPEATED = - FieldDescriptorProto_Label_LABEL_REPEATED; + using Label = FieldDescriptorProto_Label; + static constexpr Label LABEL_OPTIONAL = FieldDescriptorProto_Label_LABEL_OPTIONAL; + static constexpr Label LABEL_REQUIRED = FieldDescriptorProto_Label_LABEL_REQUIRED; + static constexpr Label LABEL_REPEATED = FieldDescriptorProto_Label_LABEL_REPEATED; static inline bool Label_IsValid(int value) { return FieldDescriptorProto_Label_IsValid(value); } - static constexpr Label Label_MIN = - FieldDescriptorProto_Label_Label_MIN; - static constexpr Label Label_MAX = - FieldDescriptorProto_Label_Label_MAX; - static constexpr int Label_ARRAYSIZE = - FieldDescriptorProto_Label_Label_ARRAYSIZE; - static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* - Label_descriptor() { + static constexpr Label Label_MIN = FieldDescriptorProto_Label_Label_MIN; + static constexpr Label Label_MAX = FieldDescriptorProto_Label_Label_MAX; + static constexpr int Label_ARRAYSIZE = FieldDescriptorProto_Label_Label_ARRAYSIZE; + static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Label_descriptor() { return FieldDescriptorProto_Label_descriptor(); } - template - static inline const std::string& Label_Name(T enum_t_value) { - static_assert(::std::is_same::value || - ::std::is_integral::value, - "Incorrect type passed to function Label_Name."); - return FieldDescriptorProto_Label_Name(enum_t_value); + template + static inline const std::string& Label_Name(T value) { + return FieldDescriptorProto_Label_Name(value); } - static inline bool Label_Parse(::absl::string_view name, - Label* value) { + static inline bool Label_Parse(absl::string_view name, Label* value) { return FieldDescriptorProto_Label_Parse(name, value); } @@ -3889,35 +3859,24 @@ class PROTOBUF_EXPORT FileOptions final : // nested types ---------------------------------------------------- - typedef FileOptions_OptimizeMode OptimizeMode; - static constexpr OptimizeMode SPEED = - FileOptions_OptimizeMode_SPEED; - static constexpr OptimizeMode CODE_SIZE = - FileOptions_OptimizeMode_CODE_SIZE; - static constexpr OptimizeMode LITE_RUNTIME = - FileOptions_OptimizeMode_LITE_RUNTIME; + using OptimizeMode = FileOptions_OptimizeMode; + static constexpr OptimizeMode SPEED = FileOptions_OptimizeMode_SPEED; + static constexpr OptimizeMode CODE_SIZE = FileOptions_OptimizeMode_CODE_SIZE; + static constexpr OptimizeMode LITE_RUNTIME = FileOptions_OptimizeMode_LITE_RUNTIME; static inline bool OptimizeMode_IsValid(int value) { return FileOptions_OptimizeMode_IsValid(value); } - static constexpr OptimizeMode OptimizeMode_MIN = - FileOptions_OptimizeMode_OptimizeMode_MIN; - static constexpr OptimizeMode OptimizeMode_MAX = - FileOptions_OptimizeMode_OptimizeMode_MAX; - static constexpr int OptimizeMode_ARRAYSIZE = - FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE; - static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* - OptimizeMode_descriptor() { + static constexpr OptimizeMode OptimizeMode_MIN = FileOptions_OptimizeMode_OptimizeMode_MIN; + static constexpr OptimizeMode OptimizeMode_MAX = FileOptions_OptimizeMode_OptimizeMode_MAX; + static constexpr int OptimizeMode_ARRAYSIZE = FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE; + static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* OptimizeMode_descriptor() { return FileOptions_OptimizeMode_descriptor(); } - template - static inline const std::string& OptimizeMode_Name(T enum_t_value) { - static_assert(::std::is_same::value || - ::std::is_integral::value, - "Incorrect type passed to function OptimizeMode_Name."); - return FileOptions_OptimizeMode_Name(enum_t_value); + template + static inline const std::string& OptimizeMode_Name(T value) { + return FileOptions_OptimizeMode_Name(value); } - static inline bool OptimizeMode_Parse(::absl::string_view name, - OptimizeMode* value) { + static inline bool OptimizeMode_Parse(absl::string_view name, OptimizeMode* value) { return FileOptions_OptimizeMode_Parse(name, value); } @@ -5043,67 +5002,45 @@ class PROTOBUF_EXPORT FieldOptions final : // nested types ---------------------------------------------------- - typedef FieldOptions_CType CType; - static constexpr CType STRING = - FieldOptions_CType_STRING; - static constexpr CType CORD = - FieldOptions_CType_CORD; - static constexpr CType STRING_PIECE = - FieldOptions_CType_STRING_PIECE; + using CType = FieldOptions_CType; + static constexpr CType STRING = FieldOptions_CType_STRING; + static constexpr CType CORD = FieldOptions_CType_CORD; + static constexpr CType STRING_PIECE = FieldOptions_CType_STRING_PIECE; static inline bool CType_IsValid(int value) { return FieldOptions_CType_IsValid(value); } - static constexpr CType CType_MIN = - FieldOptions_CType_CType_MIN; - static constexpr CType CType_MAX = - FieldOptions_CType_CType_MAX; - static constexpr int CType_ARRAYSIZE = - FieldOptions_CType_CType_ARRAYSIZE; - static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* - CType_descriptor() { + static constexpr CType CType_MIN = FieldOptions_CType_CType_MIN; + static constexpr CType CType_MAX = FieldOptions_CType_CType_MAX; + static constexpr int CType_ARRAYSIZE = FieldOptions_CType_CType_ARRAYSIZE; + static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* CType_descriptor() { return FieldOptions_CType_descriptor(); } - template - static inline const std::string& CType_Name(T enum_t_value) { - static_assert(::std::is_same::value || - ::std::is_integral::value, - "Incorrect type passed to function CType_Name."); - return FieldOptions_CType_Name(enum_t_value); + template + static inline const std::string& CType_Name(T value) { + return FieldOptions_CType_Name(value); } - static inline bool CType_Parse(::absl::string_view name, - CType* value) { + static inline bool CType_Parse(absl::string_view name, CType* value) { return FieldOptions_CType_Parse(name, value); } - typedef FieldOptions_JSType JSType; - static constexpr JSType JS_NORMAL = - FieldOptions_JSType_JS_NORMAL; - static constexpr JSType JS_STRING = - FieldOptions_JSType_JS_STRING; - static constexpr JSType JS_NUMBER = - FieldOptions_JSType_JS_NUMBER; + using JSType = FieldOptions_JSType; + static constexpr JSType JS_NORMAL = FieldOptions_JSType_JS_NORMAL; + static constexpr JSType JS_STRING = FieldOptions_JSType_JS_STRING; + static constexpr JSType JS_NUMBER = FieldOptions_JSType_JS_NUMBER; static inline bool JSType_IsValid(int value) { return FieldOptions_JSType_IsValid(value); } - static constexpr JSType JSType_MIN = - FieldOptions_JSType_JSType_MIN; - static constexpr JSType JSType_MAX = - FieldOptions_JSType_JSType_MAX; - static constexpr int JSType_ARRAYSIZE = - FieldOptions_JSType_JSType_ARRAYSIZE; - static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* - JSType_descriptor() { + static constexpr JSType JSType_MIN = FieldOptions_JSType_JSType_MIN; + static constexpr JSType JSType_MAX = FieldOptions_JSType_JSType_MAX; + static constexpr int JSType_ARRAYSIZE = FieldOptions_JSType_JSType_ARRAYSIZE; + static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* JSType_descriptor() { return FieldOptions_JSType_descriptor(); } - template - static inline const std::string& JSType_Name(T enum_t_value) { - static_assert(::std::is_same::value || - ::std::is_integral::value, - "Incorrect type passed to function JSType_Name."); - return FieldOptions_JSType_Name(enum_t_value); + template + static inline const std::string& JSType_Name(T value) { + return FieldOptions_JSType_Name(value); } - static inline bool JSType_Parse(::absl::string_view name, - JSType* value) { + static inline bool JSType_Parse(absl::string_view name, JSType* value) { return FieldOptions_JSType_Parse(name, value); } @@ -7051,35 +6988,24 @@ class PROTOBUF_EXPORT MethodOptions final : // nested types ---------------------------------------------------- - typedef MethodOptions_IdempotencyLevel IdempotencyLevel; - static constexpr IdempotencyLevel IDEMPOTENCY_UNKNOWN = - MethodOptions_IdempotencyLevel_IDEMPOTENCY_UNKNOWN; - static constexpr IdempotencyLevel NO_SIDE_EFFECTS = - MethodOptions_IdempotencyLevel_NO_SIDE_EFFECTS; - static constexpr IdempotencyLevel IDEMPOTENT = - MethodOptions_IdempotencyLevel_IDEMPOTENT; + using IdempotencyLevel = MethodOptions_IdempotencyLevel; + static constexpr IdempotencyLevel IDEMPOTENCY_UNKNOWN = MethodOptions_IdempotencyLevel_IDEMPOTENCY_UNKNOWN; + static constexpr IdempotencyLevel NO_SIDE_EFFECTS = MethodOptions_IdempotencyLevel_NO_SIDE_EFFECTS; + static constexpr IdempotencyLevel IDEMPOTENT = MethodOptions_IdempotencyLevel_IDEMPOTENT; static inline bool IdempotencyLevel_IsValid(int value) { return MethodOptions_IdempotencyLevel_IsValid(value); } - static constexpr IdempotencyLevel IdempotencyLevel_MIN = - MethodOptions_IdempotencyLevel_IdempotencyLevel_MIN; - static constexpr IdempotencyLevel IdempotencyLevel_MAX = - MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX; - static constexpr int IdempotencyLevel_ARRAYSIZE = - MethodOptions_IdempotencyLevel_IdempotencyLevel_ARRAYSIZE; - static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* - IdempotencyLevel_descriptor() { + static constexpr IdempotencyLevel IdempotencyLevel_MIN = MethodOptions_IdempotencyLevel_IdempotencyLevel_MIN; + static constexpr IdempotencyLevel IdempotencyLevel_MAX = MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX; + static constexpr int IdempotencyLevel_ARRAYSIZE = MethodOptions_IdempotencyLevel_IdempotencyLevel_ARRAYSIZE; + static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* IdempotencyLevel_descriptor() { return MethodOptions_IdempotencyLevel_descriptor(); } - template - static inline const std::string& IdempotencyLevel_Name(T enum_t_value) { - static_assert(::std::is_same::value || - ::std::is_integral::value, - "Incorrect type passed to function IdempotencyLevel_Name."); - return MethodOptions_IdempotencyLevel_Name(enum_t_value); + template + static inline const std::string& IdempotencyLevel_Name(T value) { + return MethodOptions_IdempotencyLevel_Name(value); } - static inline bool IdempotencyLevel_Parse(::absl::string_view name, - IdempotencyLevel* value) { + static inline bool IdempotencyLevel_Parse(absl::string_view name, IdempotencyLevel* value) { return MethodOptions_IdempotencyLevel_Parse(name, value); } @@ -8347,35 +8273,24 @@ class PROTOBUF_EXPORT GeneratedCodeInfo_Annotation final : // nested types ---------------------------------------------------- - typedef GeneratedCodeInfo_Annotation_Semantic Semantic; - static constexpr Semantic NONE = - GeneratedCodeInfo_Annotation_Semantic_NONE; - static constexpr Semantic SET = - GeneratedCodeInfo_Annotation_Semantic_SET; - static constexpr Semantic ALIAS = - GeneratedCodeInfo_Annotation_Semantic_ALIAS; + using Semantic = GeneratedCodeInfo_Annotation_Semantic; + static constexpr Semantic NONE = GeneratedCodeInfo_Annotation_Semantic_NONE; + static constexpr Semantic SET = GeneratedCodeInfo_Annotation_Semantic_SET; + static constexpr Semantic ALIAS = GeneratedCodeInfo_Annotation_Semantic_ALIAS; static inline bool Semantic_IsValid(int value) { return GeneratedCodeInfo_Annotation_Semantic_IsValid(value); } - static constexpr Semantic Semantic_MIN = - GeneratedCodeInfo_Annotation_Semantic_Semantic_MIN; - static constexpr Semantic Semantic_MAX = - GeneratedCodeInfo_Annotation_Semantic_Semantic_MAX; - static constexpr int Semantic_ARRAYSIZE = - GeneratedCodeInfo_Annotation_Semantic_Semantic_ARRAYSIZE; - static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* - Semantic_descriptor() { + static constexpr Semantic Semantic_MIN = GeneratedCodeInfo_Annotation_Semantic_Semantic_MIN; + static constexpr Semantic Semantic_MAX = GeneratedCodeInfo_Annotation_Semantic_Semantic_MAX; + static constexpr int Semantic_ARRAYSIZE = GeneratedCodeInfo_Annotation_Semantic_Semantic_ARRAYSIZE; + static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Semantic_descriptor() { return GeneratedCodeInfo_Annotation_Semantic_descriptor(); } - template - static inline const std::string& Semantic_Name(T enum_t_value) { - static_assert(::std::is_same::value || - ::std::is_integral::value, - "Incorrect type passed to function Semantic_Name."); - return GeneratedCodeInfo_Annotation_Semantic_Name(enum_t_value); + template + static inline const std::string& Semantic_Name(T value) { + return GeneratedCodeInfo_Annotation_Semantic_Name(value); } - static inline bool Semantic_Parse(::absl::string_view name, - Semantic* value) { + static inline bool Semantic_Parse(absl::string_view name, Semantic* value) { return GeneratedCodeInfo_Annotation_Semantic_Parse(name, value); } @@ -14884,39 +14799,46 @@ PROTOBUF_NAMESPACE_CLOSE PROTOBUF_NAMESPACE_OPEN -template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type> : ::std::true_type {}; template <> -inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type>() { +struct is_proto_enum<::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type> : std::true_type {}; +template <> +inline const EnumDescriptor* GetEnumDescriptor<::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type>() { return ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type_descriptor(); } -template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label> : ::std::true_type {}; template <> -inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label>() { +struct is_proto_enum<::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label> : std::true_type {}; +template <> +inline const EnumDescriptor* GetEnumDescriptor<::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label>() { return ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label_descriptor(); } -template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode> : ::std::true_type {}; template <> -inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode>() { +struct is_proto_enum<::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode> : std::true_type {}; +template <> +inline const EnumDescriptor* GetEnumDescriptor<::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode>() { return ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode_descriptor(); } -template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType> : ::std::true_type {}; template <> -inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType>() { +struct is_proto_enum<::PROTOBUF_NAMESPACE_ID::FieldOptions_CType> : std::true_type {}; +template <> +inline const EnumDescriptor* GetEnumDescriptor<::PROTOBUF_NAMESPACE_ID::FieldOptions_CType>() { return ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType_descriptor(); } -template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType> : ::std::true_type {}; template <> -inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType>() { +struct is_proto_enum<::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType> : std::true_type {}; +template <> +inline const EnumDescriptor* GetEnumDescriptor<::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType>() { return ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType_descriptor(); } -template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel> : ::std::true_type {}; template <> -inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel>() { +struct is_proto_enum<::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel> : std::true_type {}; +template <> +inline const EnumDescriptor* GetEnumDescriptor<::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel>() { return ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel_descriptor(); } -template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic> : ::std::true_type {}; template <> -inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic>() { +struct is_proto_enum<::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic> : std::true_type {}; +template <> +inline const EnumDescriptor* GetEnumDescriptor<::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic>() { return ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic_descriptor(); } diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index d14557cc9b..726592b946 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc @@ -559,6 +559,7 @@ TEST_F(FileDescriptorTest, CopyHeadingTo) { proto.set_name("foo.proto"); proto.set_package("foo.bar.baz"); proto.set_syntax("proto3"); + proto.mutable_options()->set_java_package("foo.bar.baz"); // Won't be copied. proto.add_message_type()->set_name("Foo"); @@ -572,6 +573,7 @@ TEST_F(FileDescriptorTest, CopyHeadingTo) { EXPECT_EQ(other.name(), "foo.proto"); EXPECT_EQ(other.package(), "foo.bar.baz"); EXPECT_EQ(other.syntax(), "proto3"); + EXPECT_EQ(other.options().java_package(), "foo.bar.baz"); EXPECT_TRUE(other.message_type().empty()); } @@ -5361,8 +5363,7 @@ TEST_F(ValidationErrorTest, InputTypeNotDefined) { " method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }" "}", - "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not defined.\n" - ); + "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not defined.\n"); } TEST_F(ValidationErrorTest, InputTypeNotAMessage) { @@ -5375,8 +5376,7 @@ TEST_F(ValidationErrorTest, InputTypeNotAMessage) { " method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }" "}", - "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not a message type.\n" - ); + "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not a message type.\n"); } TEST_F(ValidationErrorTest, OutputTypeNotDefined) { @@ -5388,8 +5388,7 @@ TEST_F(ValidationErrorTest, OutputTypeNotDefined) { " method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }" "}", - "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not defined.\n" - ); + "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not defined.\n"); } TEST_F(ValidationErrorTest, OutputTypeNotAMessage) { @@ -5402,8 +5401,8 @@ TEST_F(ValidationErrorTest, OutputTypeNotAMessage) { " method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }" "}", - "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not a message type.\n" - ); + "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not a message " + "type.\n"); } @@ -6035,8 +6034,8 @@ TEST_F(ValidationErrorTest, RollbackAfterError) { " }" "}", - "foo.proto: TestService.Baz: INPUT_TYPE: \"NoSuchType\" is not defined.\n" - ); + "foo.proto: TestService.Baz: INPUT_TYPE: \"NoSuchType\" is not " + "defined.\n"); // Make sure that if we build the same file again with the error fixed, // it works. If the above rollback was incomplete, then some symbols will diff --git a/src/google/protobuf/duration.pb.h b/src/google/protobuf/duration.pb.h index dd8cab0ca1..2c1a5503b6 100644 --- a/src/google/protobuf/duration.pb.h +++ b/src/google/protobuf/duration.pb.h @@ -15,7 +15,7 @@ #error "your headers." #endif // PROTOBUF_VERSION -#if 3021006 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021007 < PROTOBUF_MIN_PROTOC_VERSION #error "This file was generated by an older version of protoc which is" #error "incompatible with your Protocol Buffer headers. Please" #error "regenerate this file with a newer version of protoc." diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h index e134813f32..c8c03c3e5e 100644 --- a/src/google/protobuf/empty.pb.h +++ b/src/google/protobuf/empty.pb.h @@ -15,7 +15,7 @@ #error "your headers." #endif // PROTOBUF_VERSION -#if 3021006 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021007 < PROTOBUF_MIN_PROTOC_VERSION #error "This file was generated by an older version of protoc which is" #error "incompatible with your Protocol Buffer headers. Please" #error "regenerate this file with a newer version of protoc." diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc index 2db28c3f24..8ef2d2b9a4 100644 --- a/src/google/protobuf/extension_set_unittest.cc +++ b/src/google/protobuf/extension_set_unittest.cc @@ -49,6 +49,7 @@ #include "google/protobuf/testing/googletest.h" #include #include "absl/base/casts.h" +#include "absl/strings/cord.h" #include "absl/strings/match.h" #include "google/protobuf/test_util.h" #include "google/protobuf/test_util2.h" diff --git a/src/google/protobuf/field_mask.pb.h b/src/google/protobuf/field_mask.pb.h index 0b3e0b714a..13fe9cfdb3 100644 --- a/src/google/protobuf/field_mask.pb.h +++ b/src/google/protobuf/field_mask.pb.h @@ -15,7 +15,7 @@ #error "your headers." #endif // PROTOBUF_VERSION -#if 3021006 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021007 < PROTOBUF_MIN_PROTOC_VERSION #error "This file was generated by an older version of protoc which is" #error "incompatible with your Protocol Buffer headers. Please" #error "regenerate this file with a newer version of protoc." diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index b1b472cb9d..bacb9b845a 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -2491,7 +2491,7 @@ int Reflection::MapSize(const Message& message, // ----------------------------------------------------------------------------- const FieldDescriptor* Reflection::FindKnownExtensionByName( - const std::string& name) const { + absl::string_view name) const { if (!schema_.HasExtensionSet()) return nullptr; return descriptor_pool_->FindExtensionByPrintableName(descriptor_, name); } @@ -3203,6 +3203,7 @@ void Reflection::PopulateTcParseFieldAux( field_aux++->offset = schema_.SizeofSplit(); break; case internal::TailCallTableInfo::kSubTable: + case internal::TailCallTableInfo::kSubMessageWeak: GOOGLE_LOG(FATAL) << "Not supported"; break; case internal::TailCallTableInfo::kSubMessage: diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h index 3a6e93cb2c..70a75aa20d 100644 --- a/src/google/protobuf/generated_message_reflection.h +++ b/src/google/protobuf/generated_message_reflection.h @@ -386,7 +386,7 @@ PROTOBUF_EXPORT const std::string& NameOfDenseEnumSlow(int v, // very fast. This assumes all the enums fall in the range [min_val .. max_val]. template const std::string& NameOfDenseEnum(int v) { - static_assert(max_val - min_val >= 0, "Too mamny enums between min and max."); + static_assert(max_val - min_val >= 0, "Too many enums between min and max."); static DenseEnumCacheInfo deci = {/* atomic ptr */ {}, min_val, max_val, descriptor_fn}; const std::string** cache = deci.cache.load(std::memory_order_acquire ); diff --git a/src/google/protobuf/generated_message_reflection_unittest.cc b/src/google/protobuf/generated_message_reflection_unittest.cc index 75ba3f644d..83f2ec6987 100644 --- a/src/google/protobuf/generated_message_reflection_unittest.cc +++ b/src/google/protobuf/generated_message_reflection_unittest.cc @@ -56,6 +56,7 @@ #include "google/protobuf/descriptor.h" #include "google/protobuf/testing/googletest.h" #include +#include "absl/strings/cord.h" #include "google/protobuf/map_test_util.h" #include "google/protobuf/test_util.h" diff --git a/src/google/protobuf/generated_message_tctable_decl.h b/src/google/protobuf/generated_message_tctable_decl.h index b5963a299f..58bf2777e6 100644 --- a/src/google/protobuf/generated_message_tctable_decl.h +++ b/src/google/protobuf/generated_message_tctable_decl.h @@ -287,6 +287,9 @@ struct alignas(uint64_t) TcParseTableBase { const MessageLite* message_default() const { return static_cast(message_default_p); } + const MessageLite* message_default_weak() const { + return *static_cast(message_default_p); + } }; const FieldAux* field_aux(uint32_t idx) const { return reinterpret_cast(reinterpret_cast(this) + diff --git a/src/google/protobuf/generated_message_tctable_gen.cc b/src/google/protobuf/generated_message_tctable_gen.cc index b08e3c1bf5..418918077f 100644 --- a/src/google/protobuf/generated_message_tctable_gen.cc +++ b/src/google/protobuf/generated_message_tctable_gen.cc @@ -179,21 +179,30 @@ bool IsFieldEligibleForFastParsing( const TailCallTableInfo::FieldEntryInfo& entry, const TailCallTableInfo::OptionProvider& option_provider) { const auto* field = entry.field; - // Conditions which exclude a field from being handled by fast parsing - // regardless of options should be considered in IsExcludedFromFastParsing. - if (!IsDescriptorEligibleForFastParsing(field)) return false; - const auto options = option_provider.GetForField(field); - // Weak, lazy, and split fields are not handled on the fast path. - if (options.is_implicitly_weak) return false; - if (options.is_lazy) return false; - if (options.should_split) return false; + // Map, oneof, weak, and lazy fields are not handled on the fast path. + if (field->is_map() || field->real_containing_oneof() || + field->options().weak() || options.is_implicitly_weak || + options.is_lazy || options.should_split) { + return false; + } // We will check for a valid auxiliary index range later. However, we might // want to change the value we check for inlined string fields. int aux_idx = entry.aux_idx; switch (field->type()) { + case FieldDescriptor::TYPE_ENUM: + // If enum values are not validated at parse time, then this field can be + // handled on the fast path like an int32. + if (cpp::HasPreservingUnknownEnumSemantics(field)) { + break; + } + if (field->is_repeated() && field->is_packed()) { + return false; + } + break; + // Some bytes fields can be handled on fast path. case FieldDescriptor::TYPE_STRING: case FieldDescriptor::TYPE_BYTES: @@ -226,6 +235,13 @@ bool IsFieldEligibleForFastParsing( return false; } + // The largest tag that can be read by the tailcall parser is two bytes + // when varint-coded. This allows 14 bits for the numeric tag value: + // byte 0 byte 1 + // 1nnnnttt 0nnnnnnn + // ^^^^^^^ ^^^^^^^ + if (field->number() >= 1 << 11) return false; + return true; } @@ -375,8 +391,7 @@ std::vector FilterMiniParsedFields( case FieldDescriptor::TYPE_MESSAGE: case FieldDescriptor::TYPE_GROUP: // TODO(b/210762816): support remaining field types. - if (field->is_map() || field->options().weak() || - options.is_implicitly_weak || options.is_lazy) { + if (field->is_map() || field->options().weak() || options.is_lazy) { handled = false; } else { handled = true; @@ -393,9 +408,27 @@ std::vector FilterMiniParsedFields( return generated_fallback_fields; } +// We only need field names for reporting UTF-8 parsing errors, so we only +// emit them for string fields with Utf8 transform specified. +absl::string_view FieldNameForTable( + const TailCallTableInfo::FieldEntryInfo& entry) { + const auto* field = entry.field; + if (field->type() == FieldDescriptor::TYPE_STRING) { + const uint16_t xform_val = entry.type_card & field_layout::kTvMask; + + switch (xform_val) { + case field_layout::kTvUtf8: + case field_layout::kTvUtf8Debug: + return field->name(); + break; + } + } + return "?"; +} + std::vector GenerateFieldNames( const Descriptor* descriptor, - const std::vector& fields) { + const std::vector& entries) { static constexpr int kMaxNameLength = 255; std::vector out; // First, we output the size of each string, as an unsigned byte. The first @@ -403,8 +436,8 @@ std::vector GenerateFieldNames( int count = 1; out.push_back(std::min(static_cast(descriptor->full_name().size()), kMaxNameLength)); - for (const auto* field : fields) { - out.push_back(field->name().size()); + for (const auto& entry : entries) { + out.push_back(FieldNameForTable(entry).size()); ++count; } while (count & 7) { // align to an 8-byte boundary @@ -421,8 +454,9 @@ std::vector GenerateFieldNames( } out.insert(out.end(), message_name.begin(), message_name.end()); // Then we output the actual field names - for (const auto* field : fields) { - out.insert(out.end(), field->name().begin(), field->name().end()); + for (const auto& entry : entries) { + const auto& field_name = FieldNameForTable(entry); + out.insert(out.end(), field_name.begin(), field_name.end()); } return out; @@ -611,7 +645,9 @@ uint16_t MakeTypeCardForField( case FieldDescriptor::TYPE_GROUP: type_card |= 0 | fl::kMessage | fl::kRepGroup; - if (options.use_direct_tcparser_table) { + if (options.is_implicitly_weak) { + type_card |= fl::kTvWeakPtr; + } else if (options.use_direct_tcparser_table) { type_card |= fl::kTvTable; } else { type_card |= fl::kTvDefault; @@ -624,11 +660,11 @@ uint16_t MakeTypeCardForField( type_card |= fl::kMessage; if (options.is_lazy) { type_card |= fl::kRepLazy; - } else if (options.is_implicitly_weak) { - type_card |= fl::kRepIWeak; } - if (options.use_direct_tcparser_table) { + if (options.is_implicitly_weak) { + type_card |= fl::kTvWeakPtr; + } else if (options.use_direct_tcparser_table) { type_card |= fl::kTvTable; } else { type_card |= fl::kTvDefault; @@ -698,15 +734,15 @@ TailCallTableInfo::TailCallTableInfo( } else if (field->options().weak()) { // Don't generate anything for weak fields. They are handled by the // generated fallback. - } else if (options.is_implicitly_weak) { - // Implicit weak fields don't need to store a default instance pointer. } else if (options.is_lazy) { // Lazy fields are handled by the generated fallback function. } else { field_entries.back().aux_idx = aux_entries.size(); - aux_entries.push_back( - {options.use_direct_tcparser_table ? kSubTable : kSubMessage, - {field}}); + aux_entries.push_back({options.is_implicitly_weak ? kSubMessageWeak + : options.use_direct_tcparser_table + ? kSubTable + : kSubMessage, + {field}}); } } else if (field->type() == FieldDescriptor::TYPE_ENUM && !cpp::HasPreservingUnknownEnumSemantics(field)) { @@ -794,7 +830,8 @@ TailCallTableInfo::TailCallTableInfo( ); num_to_entry_table = MakeNumToEntryTable(ordered_fields); - field_name_data = GenerateFieldNames(descriptor, ordered_fields); + GOOGLE_CHECK_EQ(field_entries.size(), ordered_fields.size()); + field_name_data = GenerateFieldNames(descriptor, field_entries); // If there are no fallback fields, and at most one extension range, the // parser can use a generic fallback function. Otherwise, a message-specific diff --git a/src/google/protobuf/generated_message_tctable_gen.h b/src/google/protobuf/generated_message_tctable_gen.h index b752a80c6f..ac24dd7766 100644 --- a/src/google/protobuf/generated_message_tctable_gen.h +++ b/src/google/protobuf/generated_message_tctable_gen.h @@ -102,6 +102,7 @@ struct PROTOBUF_EXPORT TailCallTableInfo { kSplitSizeof, kSubMessage, kSubTable, + kSubMessageWeak, kEnumRange, kEnumValidator, kNumericOffset, @@ -154,49 +155,6 @@ struct PROTOBUF_EXPORT TailCallTableInfo { bool use_generated_fallback; }; -// A quick check to see if a field can be placed into the fast-table. -// This is meant to be fast but not exhaustive; options that apply to some -// fields may also exclude them. -inline bool IsDescriptorEligibleForFastParsing(const FieldDescriptor* field) { - // Map, oneof, weak, and lazy fields are not handled on the fast path. - if (field->is_map()) return false; - if (field->real_containing_oneof()) return false; - if (field->options().weak()) return false; - - switch (field->type()) { - case FieldDescriptor::TYPE_ENUM: - // If enum values are not validated at parse time, then this field can be - // handled on the fast path like an int32. - if (cpp::HasPreservingUnknownEnumSemantics(field)) { - break; - } - if (field->is_repeated() && field->is_packed()) { - return false; - } - break; - - // Some bytes fields can be handled on fast path. - case FieldDescriptor::TYPE_STRING: - case FieldDescriptor::TYPE_BYTES: - if (field->options().ctype() != FieldOptions::STRING) { - return false; - } - break; - - default: - break; - } - - // The largest tag that can be read by the tailcall parser is two bytes - // when varint-coded. This allows 14 bits for the numeric tag value: - // byte 0 byte 1 - // 1nnnnttt 0nnnnnnn - // ^^^^^^^ ^^^^^^^ - if (field->number() >= 1 << 11) return false; - - return true; -} - } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/generated_message_tctable_impl.h b/src/google/protobuf/generated_message_tctable_impl.h index 7f51966fa9..25263d5b8d 100644 --- a/src/google/protobuf/generated_message_tctable_impl.h +++ b/src/google/protobuf/generated_message_tctable_impl.h @@ -149,7 +149,6 @@ enum FieldRep : uint16_t { kRepMessage = 0, // MessageLite* kRepGroup = 1 << kRepShift, // MessageLite* (WT=3,4) kRepLazy = 2 << kRepShift, // LazyField* - kRepIWeak = 3 << kRepShift, // ImplicitWeak }; // Transform/validation (2 bits): @@ -168,8 +167,9 @@ enum TransformValidation : uint16_t { kTvUtf8 = 2 << kTvShift, // proto3 // Message fields: - kTvDefault = 1 << kTvShift, // Aux has default_instance + kTvDefault = 1 << kTvShift, // Aux has default_instance* kTvTable = 2 << kTvShift, // Aux has TcParseTableBase* + kTvWeakPtr = 3 << kTvShift, // Aux has default_instance** (for weak) }; static_assert((kTvEnum & kTvRange) != 0, diff --git a/src/google/protobuf/generated_message_tctable_lite.cc b/src/google/protobuf/generated_message_tctable_lite.cc index dab4435c4c..f8402d3495 100644 --- a/src/google/protobuf/generated_message_tctable_lite.cc +++ b/src/google/protobuf/generated_message_tctable_lite.cc @@ -256,7 +256,9 @@ absl::string_view TcParser::FieldName(const TcParseTableBase* table, const char* TcParser::MiniParse(PROTOBUF_TC_PARAM_DECL) { uint32_t tag; ptr = ReadTagInlined(ptr, &tag); - if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr; + if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) { + return Error(PROTOBUF_TC_PARAM_PASS); + } auto* entry = FindFieldEntry(table, tag >> 3); if (entry == nullptr) { @@ -850,7 +852,7 @@ PROTOBUF_NOINLINE const char* TcParser::SingularVarBigint( } const char* TcParser::FastV8S1(PROTOBUF_TC_PARAM_DECL) { - return SpecializedFastV8S1<-1, -1>(PROTOBUF_TC_PARAM_PASS); + PROTOBUF_MUSTTAIL return SpecializedFastV8S1<-1, -1>(PROTOBUF_TC_PARAM_PASS); } const char* TcParser::FastV8S2(PROTOBUF_TC_PARAM_DECL) { PROTOBUF_MUSTTAIL return SingularVarint( @@ -1284,7 +1286,7 @@ PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularString( #endif return ToParseLoop(PROTOBUF_TC_PARAM_PASS); default: - if (PROTOBUF_PREDICT_TRUE(IsStructurallyValidUTF8(field.Get()))) { + if (PROTOBUF_PREDICT_TRUE(::google::protobuf::internal::IsStructurallyValidUTF8(field.Get()))) { return ToParseLoop(PROTOBUF_TC_PARAM_PASS); } ReportFastUtf8Error(FastDecodeTag(saved_tag), table); @@ -1357,7 +1359,7 @@ PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedString( return true; default: if (PROTOBUF_PREDICT_TRUE( - IsStructurallyValidUTF8(field[field.size() - 1]))) { + ::google::protobuf::internal::IsStructurallyValidUTF8(field[field.size() - 1]))) { return true; } ReportFastUtf8Error(FastDecodeTag(expected_tag), table); @@ -1477,8 +1479,7 @@ bool TcParser::ChangeOneof(const TcParseTableBase* table, } else if (current_kind == field_layout::kFkMessage) { switch (current_rep) { case field_layout::kRepMessage: - case field_layout::kRepGroup: - case field_layout::kRepIWeak: { + case field_layout::kRepGroup: { auto& field = RefAt(msg, current_entry->offset); if (!msg->GetArenaForAllocation()) { delete field; @@ -1825,7 +1826,7 @@ bool TcParser::MpVerifyUtf8(absl::string_view wire_bytes, const TcParseTableBase* table, const FieldEntry& entry, uint16_t xform_val) { if (xform_val == field_layout::kTvUtf8) { - if (!IsStructurallyValidUTF8(wire_bytes)) { + if (!::google::protobuf::internal::IsStructurallyValidUTF8(wire_bytes)) { PrintUTF8ErrorLog(MessageName(table), FieldName(table, &entry), "parsing", false); return false; @@ -1834,7 +1835,7 @@ bool TcParser::MpVerifyUtf8(absl::string_view wire_bytes, } #ifndef NDEBUG if (xform_val == field_layout::kTvUtf8Debug) { - if (!IsStructurallyValidUTF8(wire_bytes)) { + if (!::google::protobuf::internal::IsStructurallyValidUTF8(wire_bytes)) { PrintUTF8ErrorLog(MessageName(table), FieldName(table, &entry), "parsing", false); } @@ -2035,8 +2036,14 @@ const char* TcParser::MpMessage(PROTOBUF_TC_PARAM_DECL) { return ctx->ParseMessage(field, ptr, inner_table); } else { if (need_init || field == nullptr) { - field = table->field_aux(&entry)->message_default()->New( - msg->GetArenaForAllocation()); + const MessageLite* def; + if ((type_card & field_layout::kTvMask) == field_layout::kTvDefault) { + def = table->field_aux(&entry)->message_default(); + } else { + GOOGLE_DCHECK_EQ(type_card & field_layout::kTvMask, +field_layout::kTvWeakPtr); + def = table->field_aux(&entry)->message_default_weak(); + } + field = def->New(msg->GetArenaForAllocation()); } if (is_group) { return ctx->ParseGroup(field, ptr, decoded_tag); @@ -2076,8 +2083,10 @@ const char* TcParser::MpRepeatedMessage(PROTOBUF_TC_PARAM_DECL) { } SyncHasbits(msg, hasbits, table); + auto& field = RefAt(msg, entry.offset); + const auto aux = *table->field_aux(&entry); if ((type_card & field_layout::kTvMask) == field_layout::kTvTable) { - auto* inner_table = table->field_aux(&entry)->table; + auto* inner_table = aux.table; auto& field = RefAt(msg, entry.offset); MessageLite* value = field.Add>( inner_table->default_instance); @@ -2086,9 +2095,14 @@ const char* TcParser::MpRepeatedMessage(PROTOBUF_TC_PARAM_DECL) { } return ctx->ParseMessage(value, ptr, inner_table); } else { - auto& field = RefAt(msg, entry.offset); - MessageLite* value = field.Add>( - table->field_aux(&entry)->message_default()); + const MessageLite* def; + if ((type_card & field_layout::kTvMask) == field_layout::kTvDefault) { + def = aux.message_default(); + } else { + GOOGLE_DCHECK_EQ(type_card & field_layout::kTvMask, +field_layout::kTvWeakPtr); + def = aux.message_default_weak(); + } + MessageLite* value = field.Add>(def); if (is_group) { return ctx->ParseGroup(value, ptr, decoded_tag); } diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc index 1fca15c49c..ae553825f6 100644 --- a/src/google/protobuf/io/coded_stream_unittest.cc +++ b/src/google/protobuf/io/coded_stream_unittest.cc @@ -48,6 +48,7 @@ #include #include "absl/base/casts.h" #include "google/protobuf/stubs/logging.h" +#include "absl/strings/cord.h" #include "absl/strings/string_view.h" #include "google/protobuf/io/zero_copy_stream_impl.h" diff --git a/src/google/protobuf/io/printer.cc b/src/google/protobuf/io/printer.cc index 4ea62d3789..acedbd46e1 100644 --- a/src/google/protobuf/io/printer.cc +++ b/src/google/protobuf/io/printer.cc @@ -595,7 +595,6 @@ void Printer::PrintImpl(absl::string_view format, prefix.empty() && suffix.empty(), opts, "substitution that resolves to callback cannot contain whitespace"); - IndentIfAtStart(); range_start = sink_.bytes_written(); (*fnc)(); range_end = sink_.bytes_written(); diff --git a/src/google/protobuf/io/printer.h b/src/google/protobuf/io/printer.h index fb41ef0a9a..450e90ffc8 100644 --- a/src/google/protobuf/io/printer.h +++ b/src/google/protobuf/io/printer.h @@ -879,7 +879,7 @@ auto Printer::WithDefs( return absl::nullopt; } if (auto* str = absl::get_if(&it->second)) { - return *str; + return absl::string_view(*str); } auto* f = absl::get_if>(&it->second); diff --git a/src/google/protobuf/io/tokenizer.cc b/src/google/protobuf/io/tokenizer.cc index 992d8c0b17..4d7f56cc55 100644 --- a/src/google/protobuf/io/tokenizer.cc +++ b/src/google/protobuf/io/tokenizer.cc @@ -746,6 +746,8 @@ class CommentCollector { : prev_trailing_comments_(prev_trailing_comments), detached_comments_(detached_comments), next_leading_comments_(next_leading_comments), + num_comments_(0), + has_trailing_comment_(false), has_comment_(false), is_line_comment_(false), can_attach_to_prev_(true) { @@ -797,6 +799,7 @@ class CommentCollector { if (prev_trailing_comments_ != NULL) { prev_trailing_comments_->append(comment_buffer_); } + has_trailing_comment_ = true; can_attach_to_prev_ = false; } else { if (detached_comments_ != NULL) { @@ -804,17 +807,39 @@ class CommentCollector { } } ClearBuffer(); + num_comments_++; } } void DetachFromPrev() { can_attach_to_prev_ = false; } + void MaybeDetachComment() { + int count = num_comments_; + if (has_comment_) count++; + + // If there's one comment, make sure it is detached. + if (count == 1) { + if (has_trailing_comment_ && prev_trailing_comments_ != NULL) { + std::string trail = *prev_trailing_comments_; + if (detached_comments_ != NULL) { + // push trailing comment to front of detached + detached_comments_->insert(detached_comments_->begin(), 1, trail); + } + prev_trailing_comments_->clear(); + } + // flush pending comment so it's detached instead of leading + Flush(); + } + } + private: std::string* prev_trailing_comments_; std::vector* detached_comments_; std::string* next_leading_comments_; std::string comment_buffer_; + int num_comments_; + bool has_trailing_comment_; // True if any comments were read into comment_buffer_. This can be true even // if comment_buffer_ is empty, namely if the comment was "/**/". @@ -836,6 +861,9 @@ bool Tokenizer::NextWithComments(std::string* prev_trailing_comments, CommentCollector collector(prev_trailing_comments, detached_comments, next_leading_comments); + int prev_line = line_; + int trailing_comment_end_line = -1; + if (current_.type == TYPE_START) { // Ignore unicode byte order mark(BOM) if it appears at the file // beginning. Only UTF-8 BOM (0xEF 0xBB 0xBF) is accepted. @@ -849,12 +877,14 @@ bool Tokenizer::NextWithComments(std::string* prev_trailing_comments, } } collector.DetachFromPrev(); + prev_line = -1; } else { // A comment appearing on the same line must be attached to the previous // declaration. ConsumeZeroOrMore(); switch (TryConsumeCommentStart()) { case LINE_COMMENT: + trailing_comment_end_line = line_; ConsumeLineComment(collector.GetBufferForLineComment()); // Don't allow comments on subsequent lines to be attached to a trailing @@ -863,14 +893,8 @@ bool Tokenizer::NextWithComments(std::string* prev_trailing_comments, break; case BLOCK_COMMENT: ConsumeBlockComment(collector.GetBufferForBlockComment()); - + trailing_comment_end_line = line_; ConsumeZeroOrMore(); - if (!TryConsume('\n')) { - // Oops, the next token is on the same line. If we recorded a comment - // we really have no idea which token it should be attached to. - collector.ClearBuffer(); - return Next(); - } // Don't allow comments on subsequent lines to be attached to a trailing // comment. @@ -918,6 +942,13 @@ bool Tokenizer::NextWithComments(std::string* prev_trailing_comments, // makes no sense to attach a comment to the following token. collector.Flush(); } + if (prev_line == line_ || trailing_comment_end_line == line_) { + // When previous token and this one are on the same line, or + // even if a multi-line trailing comment ends on the same line + // as this token, it's unclear to what token the comment + // should be attached. So we detach it. + collector.MaybeDetachComment(); + } return result; } break; diff --git a/src/google/protobuf/io/tokenizer_unittest.cc b/src/google/protobuf/io/tokenizer_unittest.cc index 40a24c8e9d..f4d70f0d51 100644 --- a/src/google/protobuf/io/tokenizer_unittest.cc +++ b/src/google/protobuf/io/tokenizer_unittest.cc @@ -651,10 +651,10 @@ DocCommentCase kDocCommentCases[] = { {}, ""}, - {"prev /* ignored */ next", + {"prev /* detached */ next", "", - {}, + {" detached "}, ""}, {"prev // trailing comment\n" @@ -664,6 +664,13 @@ DocCommentCase kDocCommentCases[] = { {}, ""}, + {"prev\n" + "/* leading comment */ next", + + "", + {}, + " leading comment "}, + {"prev\n" "// leading comment\n" "// line 2\n" @@ -763,6 +770,45 @@ DocCommentCase kDocCommentCases[] = { "", {}, " leading comment\n"}, + + {"prev /* many comments*/ /* all inline */ /* will be handled */ next", + + " many comments", + {" all inline "}, + " will be handled "}, + + {R"pb( + prev /* a single block comment + that spans multiple lines + is detached if it ends + on the same line as next */ next" + )pb", + + "", + {" a single block comment\n" + "that spans multiple lines\n" + "is detached if it ends\n" + "on the same line as next "}, + ""}, + + {R"pb( + prev /* trailing */ /* leading */ next" + )pb", + + " trailing ", + {}, + " leading "}, + + {R"pb( + prev /* multi-line + trailing */ /* an oddly + placed detached */ /* an oddly + placed leading */ next" + )pb", + + " multi-line\ntrailing ", + {" an oddly\nplaced detached "}, + " an oddly\nplaced leading "}, }; TEST_2D(TokenizerTest, DocComments, kDocCommentCases, kBlockSizes) { diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc index 9becd2c392..994026346e 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc @@ -41,6 +41,7 @@ #include "google/protobuf/stubs/common.h" #include "google/protobuf/stubs/logging.h" #include "absl/base/casts.h" +#include "absl/strings/cord.h" #include "absl/strings/internal/resize_uninitialized.h" // Must be included last diff --git a/src/google/protobuf/json/BUILD.bazel b/src/google/protobuf/json/BUILD.bazel new file mode 100644 index 0000000000..1339c7a973 --- /dev/null +++ b/src/google/protobuf/json/BUILD.bazel @@ -0,0 +1,275 @@ +load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") +load("//build_defs:cpp_opts.bzl", "COPTS") + +package(default_visibility = [ + "//src/google/protobuf/util:__subpackages__", +]) + +licenses(["notice"]) + +cc_library( + name = "json", + srcs = ["json.cc"], + hdrs = ["json.h"], + copts = COPTS, + strip_include_prefix = "/src", + visibility = ["//visibility:public"], + deps = [ + ":parser", + ":unparser", + "//src/google/protobuf", + "//src/google/protobuf:port_def", + "//src/google/protobuf/io", + "//src/google/protobuf/io:zero_copy_sink", + "//src/google/protobuf/util:type_resolver_util", + "@com_google_absl//absl/base", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings", + ], +) + +cc_test( + name = "json_test", + srcs = ["json_test.cc"], + copts = COPTS, + deps = [ + ":json", + "//src/google/protobuf", + "//src/google/protobuf:cc_test_protos", + "//src/google/protobuf:port_def", + "//src/google/protobuf/io", + "//src/google/protobuf/util:json_format_cc_proto", + "//src/google/protobuf/util:json_format_proto3_cc_proto", + "//src/google/protobuf/util:type_resolver_util", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_googletest//:gtest", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "test_input_stream", + testonly = True, + hdrs = ["internal/test_input_stream.h"], + copts = COPTS, + strip_include_prefix = "/src", + visibility = ["//visibility:private"], + deps = [ + "//src/google/protobuf/io", + "@com_google_absl//absl/strings", + ], +) + +cc_library( + name = "zero_copy_buffered_stream", + srcs = ["internal/zero_copy_buffered_stream.cc"], + hdrs = ["internal/zero_copy_buffered_stream.h"], + copts = COPTS, + strip_include_prefix = "/src", + visibility = ["//visibility:private"], + deps = [ + "//src/google/protobuf:port_def", + "//src/google/protobuf/io", + "@com_google_absl//absl/algorithm:container", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", + ], +) + +cc_test( + name = "zero_copy_buffered_stream_test", + srcs = ["internal/zero_copy_buffered_stream_test.cc"], + copts = COPTS, + deps = [ + ":test_input_stream", + ":zero_copy_buffered_stream", + "@com_google_absl//absl/strings", + "@com_google_googletest//:gtest", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "untyped_message", + srcs = ["internal/untyped_message.cc"], + hdrs = ["internal/untyped_message.h"], + copts = COPTS, + strip_include_prefix = "/src", + visibility = ["//visibility:private"], + deps = [ + "//src/google/protobuf", + "//src/google/protobuf:port_def", + "//src/google/protobuf:protobuf_lite", + "//src/google/protobuf/io", + "//src/google/protobuf/util:type_resolver_util", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", + "@com_google_absl//absl/types:optional", + "@com_google_absl//absl/types:span", + "@com_google_absl//absl/types:variant", + ], +) + +cc_library( + name = "lexer", + srcs = ["internal/lexer.cc"], + hdrs = ["internal/lexer.h"], + copts = COPTS, + strip_include_prefix = "/src", + visibility = ["//visibility:private"], + deps = [ + ":message_path", + ":zero_copy_buffered_stream", + "//src/google/protobuf:port_def", + "//src/google/protobuf/io", + "@com_google_absl//absl/algorithm:container", + "@com_google_absl//absl/numeric:bits", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", + ], +) + +cc_test( + name = "lexer_test", + srcs = ["internal/lexer_test.cc"], + copts = COPTS, + deps = [ + ":lexer", + ":test_input_stream", + "//src/google/protobuf/io", + "@com_google_absl//absl/algorithm:container", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", + "@com_google_absl//absl/types:variant", + "@com_google_googletest//:gtest", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "writer", + srcs = ["internal/writer.cc"], + hdrs = ["internal/writer.h"], + copts = COPTS, + strip_include_prefix = "/src", + visibility = ["//visibility:private"], + deps = [ + "//src/google/protobuf:port_def", + "//src/google/protobuf/io", + "//src/google/protobuf/io:zero_copy_sink", + "@com_google_absl//absl/algorithm:container", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", + ], +) + +cc_library( + name = "descriptor_traits", + hdrs = ["internal/descriptor_traits.h"], + copts = COPTS, + strip_include_prefix = "/src", + visibility = ["//visibility:private"], + deps = [ + ":lexer", + ":untyped_message", + "//src/google/protobuf", + "//src/google/protobuf:port_def", + "//src/google/protobuf/util:type_resolver_util", + "@com_google_absl//absl/algorithm:container", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", + "@com_google_absl//absl/types:optional", + ], +) + +cc_library( + name = "parser", + srcs = [ + "internal/parser.cc", + ], + hdrs = [ + "internal/parser.h", + "internal/parser_traits.h", + ], + copts = COPTS, + strip_include_prefix = "/src", + visibility = ["//visibility:private"], + deps = [ + ":descriptor_traits", + ":lexer", + "//src/google/protobuf", + "//src/google/protobuf:port_def", + "//src/google/protobuf/io", + "//src/google/protobuf/io:zero_copy_sink", + "//src/google/protobuf/util:type_resolver_util", + "@com_google_absl//absl/base", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", + "@com_google_absl//absl/types:optional", + "@com_google_absl//absl/types:span", + "@com_google_googletest//:gtest", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "unparser", + srcs = [ + "internal/unparser.cc", + ], + hdrs = [ + "internal/unparser.h", + "internal/unparser_traits.h", + ], + copts = COPTS, + strip_include_prefix = "/src", + visibility = ["//visibility:private"], + deps = [ + ":descriptor_traits", + ":untyped_message", + ":writer", + "//src/google/protobuf", + "//src/google/protobuf:port_def", + "//src/google/protobuf/io", + "//src/google/protobuf/util:type_resolver_util", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", + "@com_google_absl//absl/types:optional", + "@com_google_absl//absl/types:variant", + ], +) + +cc_library( + name = "message_path", + srcs = ["internal/message_path.cc"], + hdrs = ["internal/message_path.h"], + copts = COPTS, + strip_include_prefix = "/src", + visibility = ["//visibility:private"], + deps = [ + "//src/google/protobuf", + "@com_google_absl//absl/cleanup", + "@com_google_absl//absl/strings", + ], +) diff --git a/src/google/protobuf/json/internal/descriptor_traits.h b/src/google/protobuf/json/internal/descriptor_traits.h new file mode 100644 index 0000000000..2d08f3a927 --- /dev/null +++ b/src/google/protobuf/json/internal/descriptor_traits.h @@ -0,0 +1,513 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_JSON_INTERNAL_DESCRIPTOR_TRAITS_H__ +#define GOOGLE_PROTOBUF_JSON_INTERNAL_DESCRIPTOR_TRAITS_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "google/protobuf/type.pb.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/dynamic_message.h" +#include "google/protobuf/message.h" +#include "absl/algorithm/container.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/match.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "google/protobuf/json/internal/lexer.h" +#include "google/protobuf/json/internal/untyped_message.h" +#include "google/protobuf/stubs/status_macros.h" + + +// Must be included last. +#include "google/protobuf/port_def.inc" + +// Traits for working with descriptor.proto and type.proto generically. + +namespace google { +namespace protobuf { +namespace json_internal { +enum class MessageType { + kNotWellKnown, + kAny, + kWrapper, + kStruct, + kList, + kValue, + kNull, + kTimestamp, + kDuration, + kFieldMask, +}; + +inline MessageType ClassifyMessage(absl::string_view name) { + constexpr absl::string_view kWellKnownPkg = "google.protobuf."; + if (!absl::StartsWith(name, kWellKnownPkg)) { + return MessageType::kNotWellKnown; + } + name = name.substr(kWellKnownPkg.size()); + + switch (name.size()) { + case 3: + if (name == "Any") { + return MessageType::kAny; + } + break; + case 5: + if (name == "Value") { + return MessageType::kValue; + } + break; + case 6: + if (name == "Struct") { + return MessageType::kStruct; + } + break; + case 8: + if (name == "Duration") { + return MessageType::kDuration; + } + break; + case 9: + if (name == "BoolValue") { + return MessageType::kWrapper; + } + if (name == "NullValue") { + return MessageType::kNull; + } + if (name == "ListValue") { + return MessageType::kList; + } + if (name == "Timestamp") { + return MessageType::kTimestamp; + } + if (name == "FieldMask") { + return MessageType::kFieldMask; + } + break; + case 10: + if (name == "BytesValue" || name == "FloatValue" || + name == "Int32Value" || name == "Int64Value") { + return MessageType::kWrapper; + } + break; + case 11: + if (name == "DoubleValue" || name == "StringValue" || + name == "UInt32Value" || name == "UInt64Value") { + return MessageType::kWrapper; + } + break; + default: + break; + } + + return MessageType::kNotWellKnown; +} + +// Helper alias templates to avoid needing to write `typename` in function +// signatures. +template +using Field = typename Traits::Field; +template +using Desc = typename Traits::Desc; + +// Traits for proto2-ish descriptors. +struct Proto2Descriptor { + // A descriptor for introspecting the fields of a message type. + // + // Desc needs to be handled through a const Desc& in most (but not + // all, in the case of ResolverTraits) cases, so we do not include the const* + // annotation on this type. + using Desc = Descriptor; + + // A field descriptor for introspecting a single field. + // + // Field is always copyable, so this can be a pointer directly. + using Field = const FieldDescriptor*; + + /// Functions for working with descriptors. /// + + static absl::string_view TypeName(const Desc& d) { return d.full_name(); } + + static absl::optional FieldByNumber(const Desc& d, int32_t number) { + if (const auto* field = d.FindFieldByNumber(number)) { + return field; + } + return absl::nullopt; + } + + static Field MustHaveField(const Desc& d, int32_t number, + JsonLocation::SourceLocation loc = + JsonLocation::SourceLocation::current()) { + auto f = FieldByNumber(d, number); + if (!f.has_value()) { + GOOGLE_LOG(FATAL) + << absl::StrFormat( + "%s has, by definition, a field numbered %d, but it could not " + "be " + "looked up; this is a bug", + TypeName(d), number); + } + return *f; + } + + static absl::optional FieldByName(const Desc& d, + absl::string_view name) { + if (const auto* field = d.FindFieldByCamelcaseName(name)) { + return field; + } + + if (const auto* field = d.FindFieldByName(name)) { + return field; + } + + for (int i = 0; i < d.field_count(); ++i) { + const auto* field = d.field(i); + if (field->has_json_name() && field->json_name() == name) { + return field; + } + } + + return absl::nullopt; + } + + static Field KeyField(const Desc& d) { return d.map_key(); } + + static Field ValueField(const Desc& d) { return d.map_value(); } + + static size_t FieldCount(const Desc& d) { return d.field_count(); } + + static Field FieldByIndex(const Desc& d, size_t idx) { return d.field(idx); } + + static absl::optional ExtensionByName(const Desc& d, + absl::string_view name) { + auto* field = d.file()->pool()->FindExtensionByName(name); + if (field == nullptr) { + return absl::nullopt; + } + return field; + } + + /// Functions for introspecting fields. /// + + static absl::string_view FieldName(Field f) { return f->name(); } + static absl::string_view FieldJsonName(Field f) { + return f->has_json_name() ? f->json_name() : f->camelcase_name(); + } + static absl::string_view FieldFullName(Field f) { return f->full_name(); } + + static absl::string_view FieldTypeName(Field f) { + if (f->type() == FieldDescriptor::TYPE_MESSAGE) { + return f->message_type()->full_name(); + } + if (f->type() == FieldDescriptor::TYPE_ENUM) { + return f->enum_type()->full_name(); + } + return ""; + } + + static FieldDescriptor::Type FieldType(Field f) { return f->type(); } + + static int32_t FieldNumber(Field f) { return f->number(); } + + static bool Is32Bit(Field f) { + switch (f->cpp_type()) { + case FieldDescriptor::CPPTYPE_UINT32: + case FieldDescriptor::CPPTYPE_INT32: + case FieldDescriptor::CPPTYPE_ENUM: + case FieldDescriptor::CPPTYPE_FLOAT: + return true; + default: + return false; + } + } + + static const Desc& ContainingType(Field f) { return *f->containing_type(); } + + static bool IsMap(Field f) { return f->is_map(); } + + static bool IsRepeated(Field f) { return f->is_repeated(); } + + static bool IsOptional(Field f) { return f->has_presence(); } + + static bool IsExtension(Field f) { return f->is_extension(); } + + static bool IsOneof(Field f) { return f->containing_oneof() != nullptr; } + + static absl::StatusOr EnumNumberByName(Field f, + absl::string_view name, + bool case_insensitive) { + if (case_insensitive) { + for (int i = 0; i < f->enum_type()->value_count(); ++i) { + const auto* ev = f->enum_type()->value(i); + if (absl::EqualsIgnoreCase(name, ev->name())) { + return ev->number(); + } + } + return absl::InvalidArgumentError( + absl::StrFormat("unknown enum value: '%s'", name)); + } + + if (const auto* ev = f->enum_type()->FindValueByName(name)) { + return ev->number(); + } + + return absl::InvalidArgumentError( + absl::StrFormat("unknown enum value: '%s'", name)); + } + + static absl::StatusOr EnumNameByNumber(Field f, int32_t number) { + if (const auto* ev = f->enum_type()->FindValueByNumber(number)) { + return ev->name(); + } + return absl::InvalidArgumentError( + absl::StrFormat("unknown enum number: '%d'", number)); + } + + // Looks up the corresponding Desc for `f`'s type, if there is one, and + // calls `body` with it. + // + // This needs to have this funny callback API since whether or not the + // Descriptor equivalent is an owning type depends on the trait. + template + static absl::Status WithFieldType(Field f, F body) { + return body(*f->message_type()); + } + + // Like WithFieldType, but using dynamic lookup by type URL. + template + static absl::Status WithDynamicType(const Desc& desc, + const std::string& type_url, F body) { + size_t slash = type_url.rfind('/'); + if (slash == absl::string_view::npos || slash == 0) { + return absl::InvalidArgumentError(absl::StrCat( + "@type must contain at least one / and a nonempty host; got: ", + type_url)); + } + absl::string_view type_name(type_url); + type_name = type_name.substr(slash + 1); + + const Descriptor* dyn_desc = + desc.file()->pool()->FindMessageTypeByName(type_name); + if (dyn_desc == nullptr) { + return absl::InvalidArgumentError( + absl::StrFormat("could not find @type '%s'", type_url)); + } + + return body(*dyn_desc); + } +}; + +// Traits for proto3-ish deserialization. +// +// See Proto2Descriptor for API docs. +struct Proto3Type { + using Desc = ResolverPool::Message; + using Field = const ResolverPool::Field*; + + /// Functions for working with descriptors. /// + static absl::string_view TypeName(const Desc& d) { return d.proto().name(); } + + static absl::optional FieldByNumber(const Desc& d, int32_t number) { + const auto* f = d.FindField(number); + return f == nullptr ? absl::nullopt : absl::make_optional(f); + } + + static Field MustHaveField(const Desc& d, int32_t number, + JsonLocation::SourceLocation loc = + JsonLocation::SourceLocation::current()) { + auto f = FieldByNumber(d, number); + if (!f.has_value()) { + GOOGLE_LOG(FATAL) + << absl::StrFormat( + "%s has, by definition, a field numbered %d, but it could not " + "be " + "looked up; this is a bug", + TypeName(d), number); + } + return *f; + } + + static absl::optional FieldByName(const Desc& d, + absl::string_view name) { + const auto* f = d.FindField(name); + return f == nullptr ? absl::nullopt : absl::make_optional(f); + } + + static Field KeyField(const Desc& d) { return &d.FieldsByIndex()[0]; } + + static Field ValueField(const Desc& d) { return &d.FieldsByIndex()[1]; } + + static size_t FieldCount(const Desc& d) { return d.proto().fields_size(); } + + static Field FieldByIndex(const Desc& d, size_t idx) { + return &d.FieldsByIndex()[idx]; + } + + static absl::optional ExtensionByName(const Desc& d, + absl::string_view name) { + // type.proto cannot represent extensions, so this function always + // fails. + return absl::nullopt; + } + + /// Functions for introspecting fields. /// + + static absl::string_view FieldName(Field f) { return f->proto().name(); } + static absl::string_view FieldJsonName(Field f) { + return f->proto().json_name(); + } + static absl::string_view FieldFullName(Field f) { return f->proto().name(); } + + static absl::string_view FieldTypeName(Field f) { + absl::string_view url = f->proto().type_url(); + + // If there is no slash, `slash` is string_view::npos, which is guaranteed + // to be -1. + size_t slash = url.rfind('/'); + return url.substr(slash + 1); + } + + static FieldDescriptor::Type FieldType(Field f) { + // The descriptor.proto and type.proto field type enums are required to be + // the same, so we leverage this. + return static_cast(f->proto().kind()); + } + + static int32_t FieldNumber(Field f) { return f->proto().number(); } + + static bool Is32Bit(Field f) { + switch (f->proto().kind()) { + case google::protobuf::Field::TYPE_INT32: + case google::protobuf::Field::TYPE_SINT32: + case google::protobuf::Field::TYPE_UINT32: + case google::protobuf::Field::TYPE_FIXED32: + case google::protobuf::Field::TYPE_SFIXED32: + case google::protobuf::Field::TYPE_FLOAT: + return true; + default: + return false; + } + } + + static const Desc& ContainingType(Field f) { return f->parent(); } + static bool IsMap(Field f) { + if (f->proto().kind() != google::protobuf::Field::TYPE_MESSAGE) { + return false; + } + + bool value = false; + (void)WithFieldType(f, [&value](const Desc& desc) { + value = absl::c_any_of(desc.proto().options(), [&](auto& option) { + return option.name() == "map_entry"; + }); + return absl::OkStatus(); + }); + return value; + } + + static bool IsRepeated(Field f) { + return f->proto().cardinality() == + google::protobuf::Field::CARDINALITY_REPEATED; + } + + static bool IsOptional(Field f) { + return f->proto().cardinality() == + google::protobuf::Field::CARDINALITY_OPTIONAL; + } + + static bool IsExtension(Field f) { return false; } + + static bool IsOneof(Field f) { return f->proto().oneof_index() != 0; } + + static absl::StatusOr EnumNumberByName(Field f, + absl::string_view name, + bool case_insensitive) { + auto e = f->EnumType(); + RETURN_IF_ERROR(e.status()); + + for (const auto& ev : (**e).proto().enumvalue()) { + if (case_insensitive) { + // Two ifs to avoid doing operator== twice if the names are not equal. + if (absl::EqualsIgnoreCase(ev.name(), name)) { + return ev.number(); + } + } else if (ev.name() == name) { + return ev.number(); + } + } + return absl::InvalidArgumentError( + absl::StrFormat("unknown enum value: '%s'", name)); + } + + static absl::StatusOr EnumNameByNumber(Field f, int32_t number) { + auto e = f->EnumType(); + RETURN_IF_ERROR(e.status()); + + for (const auto& ev : (**e).proto().enumvalue()) { + if (ev.number() == number) { + return ev.name(); + } + } + return absl::InvalidArgumentError( + absl::StrFormat("unknown enum number: '%d'", number)); + } + + template + static absl::Status WithFieldType(Field f, F body) { + auto m = f->MessageType(); + RETURN_IF_ERROR(m.status()); + return body(**m); + } + + template + static absl::Status WithDynamicType(const Desc& desc, + const std::string& type_url, F body) { + auto dyn_desc = desc.pool()->FindMessage(type_url); + RETURN_IF_ERROR(dyn_desc.status()); + return body(**dyn_desc); + } +}; +} // namespace json_internal +} // namespace protobuf +} // namespace google + +#include "google/protobuf/port_undef.inc" +#endif // GOOGLE_PROTOBUF_JSON_INTERNAL_DESCRIPTOR_TRAITS_INTERNAL_H__ diff --git a/src/google/protobuf/json/internal/lexer.cc b/src/google/protobuf/json/internal/lexer.cc new file mode 100644 index 0000000000..63e7468737 --- /dev/null +++ b/src/google/protobuf/json/internal/lexer.cc @@ -0,0 +1,541 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/json/internal/lexer.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "google/protobuf/stubs/logging.h" +#include "google/protobuf/stubs/common.h" +#include "absl/algorithm/container.h" +#include "absl/numeric/bits.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/ascii.h" +#include "absl/strings/numbers.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" +#include "google/protobuf/stubs/status_macros.h" + +// Must be included last. +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace json_internal { +namespace { +// Randomly inserts bonus whitespace of a few different kinds into a string. +// +// This utility is intended to make error messages hostile to machine +// interpretation as a Hyrum's Law countermeasure, without potentially confusing +// human readers. +void HardenAgainstHyrumsLaw(absl::string_view to_obfuscate, std::string& out) { + // Get some simple randomness from ASLR, which is enabled in most + // environments. Our goal is to be annoying, not secure. + static const void* const kAslrSeed = &kAslrSeed; + // Per-call randomness from a relaxed atomic. + static std::atomic kCounterSeed{0}; + + constexpr uint64_t kA = 0x5851f42d4c957f2dull; + constexpr uint64_t kB = 0x14057b7ef767814full; + + uint64_t state = absl::bit_cast(kAslrSeed) + kB + + kCounterSeed.fetch_add(1, std::memory_order_relaxed); + auto rng = [&state] { + state = state * kA + kB; + return absl::rotr(static_cast(((state >> 18) ^ state) >> 27), + state >> 59); + }; + (void)rng(); // Advance state once. + + out.reserve(to_obfuscate.size() + absl::c_count(to_obfuscate, ' ')); + for (char c : to_obfuscate) { + out.push_back(c); + if (c != ' ' || rng() % 3 != 0) { + continue; + } + + size_t count = rng() % 2 + 1; + for (size_t i = 0; i < count; ++i) { + out.push_back(' '); + } + } +} +} // namespace + +constexpr size_t ParseOptions::kDefaultDepth; + +absl::Status JsonLocation::Invalid(absl::string_view message, + SourceLocation sl) const { + // NOTE: we intentionally do not harden the "invalid JSON" part, so that + // people have a hope of grepping for it in logs. That part is easy to + // commit to, as stability goes. + // + // This copies the error twice. Because this is the "unhappy" path, this + // function is cold and can afford the waste. + std::string status_message = "invalid JSON"; + std::string to_obfuscate; + if (path != nullptr) { + absl::StrAppend(&to_obfuscate, " in "); + path->Describe(to_obfuscate); + to_obfuscate.push_back(','); + } + absl::StrAppendFormat(&to_obfuscate, " near %zu:%zu (offset %zu): %s", + line + 1, col + 1, offset, message); + HardenAgainstHyrumsLaw(to_obfuscate, status_message); + + return absl::InvalidArgumentError(std::move(status_message)); +} + +absl::StatusOr JsonLexer::PeekKind() { + RETURN_IF_ERROR(SkipToToken()); + char c = stream_.PeekChar(); + switch (c) { + case '{': + return JsonLexer::kObj; + case '[': + return JsonLexer::kArr; + case '"': + case '\'': + return JsonLexer::kStr; + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return JsonLexer::kNum; + case 't': + return JsonLexer::kTrue; + case 'f': + return JsonLexer::kFalse; + case 'n': + return JsonLexer::kNull; + default: + return Invalid(absl::StrFormat("unexpected character: '%c'", c)); + } +} + +absl::Status JsonLexer::SkipValue() { + absl::StatusOr kind = PeekKind(); + RETURN_IF_ERROR(kind.status()); + + switch (*kind) { + case JsonLexer::kObj: + return VisitObject( + [this](LocationWith&) { return SkipValue(); }); + case JsonLexer::kArr: + return VisitArray([this] { return SkipValue(); }); + case JsonLexer::kStr: + return ParseUtf8().status(); + case JsonLexer::kNum: + return ParseNumber().status(); + case JsonLexer::kTrue: + return Expect("true"); + case JsonLexer::kFalse: + return Expect("false"); + case JsonLexer::kNull: + return Expect("null"); + default: + break; + } + // Some compilers seem to fail to realize this is a basic block + // terminator and incorrectly believe this function is missing + // a return. + GOOGLE_CHECK(false) << "unreachable"; + return absl::OkStatus(); +} + +absl::StatusOr JsonLexer::ParseU16HexCodepoint() { + absl::StatusOr> escape = Take(4); + RETURN_IF_ERROR(escape.status()); + + uint16_t u16 = 0; + for (char c : escape->value.AsView()) { + if (c >= '0' && c <= '9') { + c -= '0'; + } else if (c >= 'a' && c <= 'f') { + c = c - 'a' + 10; + } else if (c >= 'A' && c <= 'F') { + c = c - 'A' + 10; + } else { + return Invalid("invalid Unicode escape"); + } + u16 <<= 4; + u16 |= c; + } + + return u16; +} + +absl::Status JsonLexer::SkipToToken() { + while (true) { + RETURN_IF_ERROR(stream_.BufferAtLeast(1).status()); + switch (stream_.PeekChar()) { + case '\n': + RETURN_IF_ERROR(Advance(1)); + ++json_loc_.line; + json_loc_.col = 0; + break; + case '\r': + case '\t': + case ' ': + RETURN_IF_ERROR(Advance(1)); + break; + default: + return absl::OkStatus(); + } + } +} + +absl::StatusOr> JsonLexer::ParseRawNumber() { + RETURN_IF_ERROR(SkipToToken()); + + enum { kInt, kFraction, kExponent } state = kInt; + char prev_var = 0; + auto number = TakeWhile([state, prev_var](size_t index, char c) mutable { + char prev = prev_var; + prev_var = c; + if (absl::ascii_isdigit(c)) { + return true; + } + + bool last_was_int = absl::ascii_isdigit(prev); + // These checks handle transitions between the integer, fractional, and + // exponent part of a number. This will cut off at the first syntax error. + // Because all numbers must be followed by `,`, `]`, or `}`, we can let + // that catch what's left behind. + if (state == kInt && c == '-') { + return !last_was_int; + } + if (state == kInt && last_was_int && c == '.') { + state = kFraction; + return true; + } + if (state != kExponent && last_was_int && (c == 'e' || c == 'E')) { + state = kExponent; + return true; + } + if ((prev == 'e' || prev == 'E') && (c == '-' || c == '+')) { + return true; + } + + return false; + }); + + RETURN_IF_ERROR(number.status()); + absl::string_view number_text = number->value.AsView(); + + if (number_text.empty() || number_text == "-") { + return number->loc.Invalid("expected a number"); + } + + auto without_minus = + number_text[0] == '-' ? number_text.substr(1) : number_text; + if (without_minus.size() > 1 && without_minus[0] == '0' && + absl::ascii_isdigit(without_minus[1])) { + return number->loc.Invalid("number cannot have extraneous leading zero"); + } + + if (number_text.back() == '.') { + return number->loc.Invalid("number cannot have trailing period"); + } + + double d; + if (!absl::SimpleAtod(number_text, &d) || !std::isfinite(d)) { + return number->loc.Invalid( + absl::StrFormat("invalid number: '%s'", number_text)); + } + + // Find the next token, to make sure we didn't leave something behind we + // shouldn't have. + if (!stream_.AtEof()) { + RETURN_IF_ERROR(SkipToToken()); + switch (stream_.PeekChar()) { + case ',': + case ']': + case '}': + break; + default: + return Invalid( + absl::StrFormat("unexpected character: '%c'", stream_.PeekChar())); + } + } + + return number; +} + +absl::StatusOr> JsonLexer::ParseNumber() { + auto number = ParseRawNumber(); + RETURN_IF_ERROR(number.status()); + + double d; + if (!absl::SimpleAtod(number->value.AsView(), &d) || !std::isfinite(d)) { + return number->loc.Invalid( + absl::StrFormat("invalid number: '%s'", number->value.AsView())); + } + + return LocationWith{d, number->loc}; +} + +absl::StatusOr JsonLexer::ParseUnicodeEscape(char out_utf8[4]) { + auto hex = ParseU16HexCodepoint(); + RETURN_IF_ERROR(hex.status()); + + uint32_t rune = *hex; + if (rune >= 0xd800 && rune <= 0xdbff) { + // Surrogate pair: two 16-bit codepoints become a 32-bit codepoint. + uint32_t high = rune; + + RETURN_IF_ERROR(Expect("\\u")); + auto hex = ParseU16HexCodepoint(); + RETURN_IF_ERROR(hex.status()); + + uint32_t low = *hex; + if (low < 0xdc00 || low > 0xdfff) { + return Invalid("invalid low surrogate"); + } + + rune = (high & 0x3ff) << 10; + rune |= (low & 0x3ff); + rune += 0x10000; + } else if (rune >= 0xdc00 && rune <= 0xdfff) { + return Invalid("unpaired low surrogate"); + } + + // Write as UTF-8. + if (rune <= 0x7f) { + out_utf8[0] = rune; + return 1; + } else if (rune <= 0x07ff) { + out_utf8[0] = ((rune >> 6) & 0x1f) | 0xc0; + out_utf8[1] = ((rune >> 0) & 0x3f) | 0x80; + return 2; + } else if (rune <= 0xffff) { + out_utf8[0] = ((rune >> 12) & 0x0f) | 0xe0; + out_utf8[1] = ((rune >> 6) & 0x3f) | 0x80; + out_utf8[2] = ((rune >> 0) & 0x3f) | 0x80; + return 3; + } else if (rune < 0x10ffff) { + out_utf8[0] = ((rune >> 18) & 0x07) | 0xF0; + out_utf8[1] = ((rune >> 12) & 0x3f) | 0x80; + out_utf8[2] = ((rune >> 6) & 0x3f) | 0x80; + out_utf8[3] = ((rune >> 0) & 0x3f) | 0x80; + return 4; + } else { + return Invalid("invalid codepoint"); + } +} + +static char ParseSimpleEscape(char c, bool allow_legacy_syntax) { + switch (c) { + case '"': + return '"'; + case '\\': + return '\\'; + case '/': + return '/'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case '\'': + if (allow_legacy_syntax) { + return '\''; + } + ABSL_FALLTHROUGH_INTENDED; + default: + return 0; + } +} + +absl::StatusOr> JsonLexer::ParseUtf8() { + RETURN_IF_ERROR(SkipToToken()); + // This is a non-standard extension accepted by the ESF parser that we will + // need to accept for backwards-compat. + bool is_single_quote = stream_.PeekChar() == '\''; + if (!options_.allow_legacy_syntax && is_single_quote) { + return Invalid("expected '\"'"); + } + + JsonLocation loc = json_loc_; + RETURN_IF_ERROR(Expect(is_single_quote ? "'" : "\"")); + + // on_heap is empty if we do not need to heap-allocate the string. + std::string on_heap; + LocationWith mark = BeginMark(); + while (true) { + RETURN_IF_ERROR(stream_.BufferAtLeast(1).status()); + + char c = stream_.PeekChar(); + RETURN_IF_ERROR(Advance(1)); + switch (c) { + case '"': + case '\'': { + if (c != (is_single_quote ? '\'' : '"')) { + goto normal_character; + } + + if (!on_heap.empty()) { + return LocationWith{ + MaybeOwnedString(std::move(on_heap)), loc}; + } + // NOTE: the 1 below clips off the " from the end of the string. + return LocationWith{mark.value.UpToUnread(1), loc}; + } + case '\\': { + if (on_heap.empty()) { + // The 1 skips over the `\`. + on_heap = std::string(mark.value.UpToUnread(1).AsView()); + // Clang-tidy incorrectly notes this as being moved-from multiple + // times, but it can only occur in one loop iteration. The mark is + // destroyed only if we need to handle an escape when on_heap is + // empty. Because this branch unconditionally pushes to on_heap, this + // condition can never be reached in any iteration that follows it. + // This, at most one move every actually occurs. + std::move(mark).value.Discard(); + } + RETURN_IF_ERROR(stream_.BufferAtLeast(1).status()); + + char c = stream_.PeekChar(); + RETURN_IF_ERROR(Advance(1)); + if (c == 'u' || (c == 'U' && options_.allow_legacy_syntax)) { + // Ensure there is actual space to scribble the UTF-8 onto. + on_heap.resize(on_heap.size() + 4); + auto written = ParseUnicodeEscape(&on_heap[on_heap.size() - 4]); + RETURN_IF_ERROR(written.status()); + on_heap.resize(on_heap.size() - 4 + *written); + } else { + char escape = ParseSimpleEscape(c, options_.allow_legacy_syntax); + if (escape == 0) { + return Invalid(absl::StrFormat("invalid escape char: '%c'", c)); + } + on_heap.push_back(escape); + } + break; + } + normal_character: + default: { + uint8_t uc = static_cast(c); + // If people have newlines in their strings, that's their problem; it + // is too difficult to support correctly in our location tracking, and + // is out of spec, so users will get slightly wrong locations in errors. + if ((uc < 0x20 || uc == 0xff) && !options_.allow_legacy_syntax) { + return Invalid(absl::StrFormat( + "invalid control character 0x%02x in string", uc)); + } + + // Verify this is valid UTF-8. UTF-8 is a varint encoding satisfying + // one of the following (big-endian) patterns: + // + // 0b0xxxxxxx + // 0b110xxxxx'10xxxxxx + // 0b1110xxxx'10xxxxxx'10xxxxxx + // 0b11110xxx'10xxxxxx'10xxxxxx'10xxxxxx + // + // We don't need to decode it; just validate it. + size_t lookahead = 0; + switch (absl::countl_one(uc)) { + case 0: + break; + case 2: + lookahead = 1; + break; + case 3: + lookahead = 2; + break; + case 4: + lookahead = 3; + break; + default: + return Invalid("invalid UTF-8 in string"); + } + + if (!on_heap.empty()) { + on_heap.push_back(c); + } + for (int i = 0; i < lookahead; ++i) { + RETURN_IF_ERROR(stream_.BufferAtLeast(1).status()); + uint8_t uc = static_cast(stream_.PeekChar()); + if ((uc >> 6) != 2) { + return Invalid("invalid UTF-8 in string"); + } + if (!on_heap.empty()) { + on_heap.push_back(stream_.PeekChar()); + } + RETURN_IF_ERROR(Advance(1)); + } + break; + } + } + } + + return Invalid("EOF inside string"); +} + +absl::StatusOr> JsonLexer::ParseBareWord() { + RETURN_IF_ERROR(SkipToToken()); + auto ident = TakeWhile( + [](size_t, char c) { return c == '_' || absl::ascii_isalnum(c); }); + RETURN_IF_ERROR(ident.status()); + absl::string_view text = ident->value.AsView(); + + if (text.empty() || absl::ascii_isdigit(text[0]) || text == "null" || + text == "true" || text == "false") { + return ident->loc.Invalid("expected bare word"); + } + return ident; +} + +} // namespace json_internal +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/json/internal/lexer.h b/src/google/protobuf/json/internal/lexer.h new file mode 100644 index 0000000000..a4631cc676 --- /dev/null +++ b/src/google/protobuf/json/internal/lexer.h @@ -0,0 +1,361 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Internal JSON tokenization utilities; not public API. +#ifndef GOOGLE_PROTOBUF_JSON_INTERNAL_LEXER_H__ +#define GOOGLE_PROTOBUF_JSON_INTERNAL_LEXER_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "google/protobuf/stubs/logging.h" +#include "google/protobuf/stubs/common.h" +#include "google/protobuf/descriptor.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/match.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" +#include "google/protobuf/io/zero_copy_stream.h" +#include "google/protobuf/json/internal/message_path.h" +#include "google/protobuf/json/internal/zero_copy_buffered_stream.h" +#include "google/protobuf/stubs/status_macros.h" + + +// Must be included last. +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace json_internal { +// This is a duplicate of JsonParseOptions from json_util.h; it must be +// re-defined here so that :json_lexer does not need to depend on :json_util. +struct ParseOptions { + bool ignore_unknown_fields = false; + bool case_insensitive_enum_parsing = false; + + static constexpr size_t kDefaultDepth = 100; + + // The number of times we may recurse before bailing out on the grounds of + // avoiding pathological input. + int recursion_depth = kDefaultDepth; + + // The original parser used by json_util2 accepted a number of non-standard + // options. Setting this flag enables them. + // + // What those extensions were is explicitly not documented, beyond what exists + // in the unit tests; we intend to remove this setting eventually. See + // b/234868512. + bool allow_legacy_syntax = false; +}; + +// A position in JSON input, for error context. +struct JsonLocation { + // This type exists to work around an absl type that has not yet been + // released. + struct SourceLocation { + static SourceLocation current() { return {}; } + }; + + // Line and column are both zero-indexed in-memory. + size_t offset = 0; + size_t line = 0; + size_t col = 0; + const MessagePath* path = nullptr; + + // Creates an absl::InvalidArgumentError with line/column information. + absl::Status Invalid(absl::string_view message, + SourceLocation sl = SourceLocation::current()) const; +}; + +template +struct LocationWith { + T value; + JsonLocation loc; +}; + +class JsonLexer { + public: + // A kind of token that PeekKind() can detect. + enum Kind { + kObj, + kArr, + kStr, + kNum, + kTrue, + kFalse, + kNull, + }; + + using SourceLocation = JsonLocation::SourceLocation; + + JsonLexer(io::ZeroCopyInputStream* stream, const ParseOptions& options, + MessagePath* path = nullptr, JsonLocation start = {}) + : stream_(stream), options_(options), json_loc_(start), path_(path) { + json_loc_.path = path_; + } + + const ParseOptions& options() const { return options_; } + + const MessagePath& path() const { return *path_; } + MessagePath& path() { return *path_; } + + // Creates an absl::InvalidArgumentError with line/column information. + absl::Status Invalid(absl::string_view message, + SourceLocation sl = SourceLocation::current()) { + return json_loc_.Invalid(message, sl); + } + + // Expects the next bytes to be parsed (after consuming whitespace) to be + // exactly `literal`. If they are, consumes them; otherwise returns an error. + absl::Status Expect(absl::string_view literal, + SourceLocation sl = SourceLocation::current()) { + RETURN_IF_ERROR(SkipToToken()); + auto buffering = stream_.BufferAtLeast(literal.size()); + RETURN_IF_ERROR(buffering.status()); + + if (!absl::StartsWith(stream_.Unread(), literal)) { + return Invalid( + absl::StrFormat("unexpected character: '%c'; expected '%s'", + stream_.PeekChar(), literal), + sl); + } + + return Advance(literal.size()); + } + + // Like Expect(), but returns a boolean. This makes it clear that the + // lookahead is failible. + bool Peek(absl::string_view literal) { + // Suppress the error; this can only fail on EOF in which case we would + // return false regardless. + (void)SkipToToken(); + auto ignored = stream_.BufferAtLeast(literal.size()); + if (!absl::StartsWith(stream_.Unread(), literal)) { + return false; + } + + // We just ensured we had enough buffered so we can suppress this error. + (void)Advance(literal.size()); + return true; + } + + // Like Peek(string), but returns true if and only if a token of the given + // kind can be lexed next. Returns false on EOF, just like Peek(string). + bool Peek(Kind needle) { + auto kind = PeekKind(); + return kind.ok() && *kind == needle; + } + + // Consumes all whitespace and other ignored characters until the next + // token. + // + // This function returns an error on EOF, so PeekChar() can be safely + // called if it returns ok. + absl::Status SkipToToken(); + + // Returns which kind of value token (i.e., something that can occur after + // a `:`) is next up to be parsed. + absl::StatusOr PeekKind(); + + // Parses a JSON number. + absl::StatusOr> ParseNumber(); + + // Parses a number as a string, without turning it into an integer. + absl::StatusOr> ParseRawNumber(); + + // Parses a UTF-8 string. If the contents of the string happen to actually be + // UTF-8, it will return a zero-copy view; otherwise it will allocate. + absl::StatusOr> ParseUtf8(); + + // Walks over an array, calling `f` each time an element is reached. + // + // `f` should have type `() -> absl::Status`. + template + absl::Status VisitArray(F f); + + // Walks over an object, calling `f` just after parsing each `:`. + // + // `f` should have type `(absl::string_view) -> absl::Status`. + template + absl::Status VisitObject(F f); + + // Parses a single value and discards it. + absl::Status SkipValue(); + + // Forwards of functions from ZeroCopyBufferedStream. + + bool AtEof() { + // Ignore whitespace for the purposes of finding the EOF. This will return + // an error if we hit EOF, so we discard it. + (void)SkipToToken(); + return stream_.AtEof(); + } + + absl::StatusOr> Take(size_t len) { + JsonLocation loc = json_loc_; + auto taken = stream_.Take(len); + RETURN_IF_ERROR(taken.status()); + return LocationWith{*std::move(taken), loc}; + } + + template + absl::StatusOr> TakeWhile(Pred p) { + JsonLocation loc = json_loc_; + auto taken = stream_.TakeWhile(std::move(p)); + RETURN_IF_ERROR(taken.status()); + return LocationWith{*std::move(taken), loc}; + } + + LocationWith BeginMark() { return {stream_.BeginMark(), json_loc_}; } + + private: + friend BufferingGuard; + friend Mark; + friend MaybeOwnedString; + + absl::Status Push() { + if (options_.recursion_depth == 0) { + return Invalid("JSON content was too deeply nested"); + } + --options_.recursion_depth; + return absl::OkStatus(); + } + + void Pop() { ++options_.recursion_depth; } + + // Parses the next four bytes as a 16-bit hex numeral. + absl::StatusOr ParseU16HexCodepoint(); + + // Parses a Unicode escape (\uXXXX); this may be a surrogate pair, so it may + // consume the character that follows. Both are encoded as utf8 into + // `out_utf8`; returns the number of bytes written. + absl::StatusOr ParseUnicodeEscape(char out_utf8[4]); + + // Parses an alphanumeric "identifier", for use with the non-standard + // "unquoted keys" extension. + absl::StatusOr> ParseBareWord(); + + absl::Status Advance(size_t bytes) { + RETURN_IF_ERROR(stream_.Advance(bytes)); + json_loc_.offset += static_cast(bytes); + json_loc_.col += static_cast(bytes); + return absl::OkStatus(); + } + + ZeroCopyBufferedStream stream_; + + ParseOptions options_; + JsonLocation json_loc_; + MessagePath* path_; +}; + +template +absl::Status JsonLexer::VisitArray(F f) { + RETURN_IF_ERROR(Expect("[")); + RETURN_IF_ERROR(Push()); + + if (Peek("]")) { + Pop(); + return absl::OkStatus(); + } + + bool has_comma = true; + do { + if (!has_comma) { + return Invalid("expected ','"); + } + RETURN_IF_ERROR(f()); + has_comma = Peek(","); + } while (!Peek("]")); + + if (!options_.allow_legacy_syntax && has_comma) { + return Invalid("expected ']'"); + } + + Pop(); + return absl::OkStatus(); +} + +// Walks over an object, calling `f` just after parsing each `:`. +// +// `f` should have type `(MaybeOwnedString&) -> absl::Status`. +template +absl::Status JsonLexer::VisitObject(F f) { + RETURN_IF_ERROR(Expect("{")); + RETURN_IF_ERROR(Push()); + + if (Peek("}")) { + Pop(); + return absl::OkStatus(); + } + + bool has_comma = true; + do { + if (!has_comma) { + return Invalid("expected ','"); + } + RETURN_IF_ERROR(SkipToToken()); + + absl::StatusOr> key; + if (stream_.PeekChar() == '"' || stream_.PeekChar() == '\'') { + key = ParseUtf8(); + } else if (options_.allow_legacy_syntax) { + key = ParseBareWord(); + } else { + return Invalid("expected '\"'"); + } + + RETURN_IF_ERROR(key.status()); + RETURN_IF_ERROR(Expect(":")); + RETURN_IF_ERROR(f(*key)); + has_comma = Peek(","); + } while (!Peek("}")); + Pop(); + + if (!options_.allow_legacy_syntax && has_comma) { + return Invalid("expected '}'"); + } + + return absl::OkStatus(); +} +} // namespace json_internal +} // namespace protobuf +} // namespace google + +#include "google/protobuf/port_undef.inc" +#endif // GOOGLE_PROTOBUF_JSON_INTERNAL_LEXER_H__ diff --git a/src/google/protobuf/json/internal/lexer_test.cc b/src/google/protobuf/json/internal/lexer_test.cc new file mode 100644 index 0000000000..92a6f3aa2d --- /dev/null +++ b/src/google/protobuf/json/internal/lexer_test.cc @@ -0,0 +1,740 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/json/internal/lexer.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "google/protobuf/stubs/logging.h" +#include "google/protobuf/stubs/common.h" +#include +#include +#include "absl/algorithm/container.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/ascii.h" +#include "absl/strings/escaping.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" +#include "absl/strings/str_replace.h" +#include "absl/strings/string_view.h" +#include "absl/types/variant.h" +#include "google/protobuf/io/zero_copy_stream.h" +#include "google/protobuf/io/zero_copy_stream_impl_lite.h" +#include "google/protobuf/json/internal/test_input_stream.h" +#include "google/protobuf/stubs/status_macros.h" + +// Must be included last. +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace json_internal { +namespace { +using ::testing::_; +using ::testing::ElementsAre; +using ::testing::Field; +using ::testing::HasSubstr; +using ::testing::IsEmpty; +using ::testing::Pair; +using ::testing::SizeIs; +using ::testing::VariantWith; + +// TODO(b/234474291): Use the gtest versions once that's available in OSS. +MATCHER_P(IsOkAndHolds, inner, + absl::StrCat("is OK and holds ", testing::PrintToString(inner))) { + if (!arg.ok()) { + *result_listener << arg.status(); + return false; + } + return testing::ExplainMatchResult(inner, *arg, result_listener); +} + +// absl::Status GetStatus(const absl::Status& s) { return s; } +template +absl::Status GetStatus(const absl::StatusOr& s) { + return s.status(); +} + +MATCHER_P(StatusIs, status, + absl::StrCat(".status() is ", testing::PrintToString(status))) { + return GetStatus(arg).code() == status; +} + +#define EXPECT_OK(x) EXPECT_THAT(x, StatusIs(absl::StatusCode::kOk)) +#define ASSERT_OK(x) ASSERT_THAT(x, StatusIs(absl::StatusCode::kOk)) + +// TODO(b/234868512): There are several tests that validate non-standard +// behavior that is assumed to be present in the wild due to Hyrum's Law. These +// tests are grouped under the `NonStandard` suite. These tests ensure the +// non-standard syntax is accepted, and that disabling legacy mode rejects them. +// +// All other tests are strictly-conforming. + +// A generic JSON value, which is gtest-matcher friendly and stream-printable. +struct Value { + static absl::StatusOr Parse(io::ZeroCopyInputStream* stream, + ParseOptions options = {}) { + JsonLexer lex(stream, options); + return Parse(lex); + } + static absl::StatusOr Parse(JsonLexer& lex) { + absl::StatusOr kind = lex.PeekKind(); + RETURN_IF_ERROR(kind.status()); + + switch (*kind) { + case JsonLexer::kNull: + RETURN_IF_ERROR(lex.Expect("null")); + return Value{Null{}}; + case JsonLexer::kFalse: + RETURN_IF_ERROR(lex.Expect("false")); + return Value{false}; + case JsonLexer::kTrue: + RETURN_IF_ERROR(lex.Expect("true")); + return Value{true}; + case JsonLexer::kNum: { + absl::StatusOr> num = lex.ParseNumber(); + RETURN_IF_ERROR(num.status()); + return Value{num->value}; + } + case JsonLexer::kStr: { + absl::StatusOr> str = lex.ParseUtf8(); + RETURN_IF_ERROR(str.status()); + return Value{str->value.ToString()}; + } + case JsonLexer::kArr: { + std::vector arr; + absl::Status s = lex.VisitArray([&arr, &lex]() -> absl::Status { + absl::StatusOr val = Value::Parse(lex); + RETURN_IF_ERROR(val.status()); + arr.emplace_back(*std::move(val)); + return absl::OkStatus(); + }); + RETURN_IF_ERROR(s); + return Value{std::move(arr)}; + } + case JsonLexer::kObj: { + std::vector> obj; + absl::Status s = lex.VisitObject( + [&obj, &lex](LocationWith& key) -> absl::Status { + absl::StatusOr val = Value::Parse(lex); + RETURN_IF_ERROR(val.status()); + obj.emplace_back(std::move(key.value.ToString()), + *std::move(val)); + return absl::OkStatus(); + }); + RETURN_IF_ERROR(s); + return Value{std::move(obj)}; + } + } + } + + friend std::ostream& operator<<(std::ostream& os, const Value& v) { + if (absl::holds_alternative(v.value)) { + os << "null"; + } else if (const auto* x = absl::get_if(&v.value)) { + os << "bool:" << (*x ? "true" : "false"); + } else if (const auto* x = absl::get_if(&v.value)) { + os << "num:" << *x; + } else if (const auto* x = absl::get_if(&v.value)) { + os << "str:" << absl::CHexEscape(*x); + } else if (const auto* x = absl::get_if(&v.value)) { + os << "arr:["; + bool first = true; + for (const auto& val : *x) { + if (!first) { + os << ", "; + } + os << val; + } + os << "]"; + } else if (const auto* x = absl::get_if(&v.value)) { + os << "obj:["; + bool first = true; + for (const auto& kv : *x) { + if (!first) { + os << ", "; + first = false; + } + os << kv.first << ":" << kv.second; + } + os << "]"; + } + return os; + } + + struct Null {}; + using Array = std::vector; + using Object = std::vector>; + absl::variant value; +}; + +template +testing::Matcher ValueIs(M inner) { + return Field(&Value::value, VariantWith(inner)); +} + +// Executes `test` once for each three-segment split of `json`. +void Do(absl::string_view json, + std::function test, + bool verify_all_consumed = true) { + SCOPED_TRACE(absl::StrCat("json: ", absl::CHexEscape(json))); + + for (size_t i = 0; i < json.size(); ++i) { + for (size_t j = 0; j < json.size() - i + 1; ++j) { + SCOPED_TRACE(absl::StrFormat("json[0:%d], json[%d:%d], json[%d:%d]", i, i, + i + j, i + j, json.size())); + std::string first(json.substr(0, i)); + std::string second(json.substr(i, j)); + std::string third(json.substr(i + j)); + + TestInputStream in = {first, second, third}; + test(&in); + if (testing::Test::HasFailure()) { + return; + } + + if (verify_all_consumed) { + if (!absl::c_all_of(third, + [](char c) { return absl::ascii_isspace(c); })) { + ASSERT_GE(in.Consumed(), 3); + } else if (!absl::c_all_of( + second, [](char c) { return absl::ascii_isspace(c); })) { + ASSERT_GE(in.Consumed(), 2); + } else { + ASSERT_GE(in.Consumed(), 1); + } + } + } + } +} + +void BadInner(absl::string_view json, ParseOptions opts = {}) { + Do( + json, + [=](io::ZeroCopyInputStream* stream) { + EXPECT_THAT(Value::Parse(stream, opts), + StatusIs(absl::StatusCode::kInvalidArgument)); + }, + false); +} + +// Like Do, but runs a legacy syntax test twice: once with legacy settings, once +// without. For the latter, the test is expected to fail; for the former, +// `test` is called so it can run expectations. +void DoLegacy(absl::string_view json, std::function test) { + Do(json, [&](io::ZeroCopyInputStream* stream) { + ParseOptions options; + options.allow_legacy_syntax = true; + auto value = Value::Parse(stream, options); + ASSERT_OK(value); + test(*value); + }); + BadInner(json); +} + +// Like Bad, but ensures json fails to parse in both modes. +void Bad(absl::string_view json) { + ParseOptions options; + options.allow_legacy_syntax = true; + BadInner(json, options); + BadInner(json); +} + +TEST(LexerTest, Null) { + Do("null", [](io::ZeroCopyInputStream* stream) { + EXPECT_THAT(Value::Parse(stream), IsOkAndHolds(ValueIs(_))); + }); +} + +TEST(LexerTest, False) { + Do("false", [](io::ZeroCopyInputStream* stream) { + EXPECT_THAT(Value::Parse(stream), IsOkAndHolds(ValueIs(false))); + }); +} + +TEST(LexerTest, True) { + Do("true", [](io::ZeroCopyInputStream* stream) { + EXPECT_THAT(Value::Parse(stream), IsOkAndHolds(ValueIs(true))); + }); +} + +TEST(LexerTest, Typos) { + Bad("-"); + Bad("-foo"); + Bad("nule"); +} + +TEST(LexerTest, UnknownCharacters) { + Bad("*"); + Bad("[*]"); + Bad("{key: *}"); +} + +TEST(LexerTest, EmptyString) { + Do(R"json("")json", [](io::ZeroCopyInputStream* stream) { + EXPECT_THAT(Value::Parse(stream), + IsOkAndHolds(ValueIs(IsEmpty()))); + }); +} + +TEST(LexerTest, SimpleString) { + Do(R"json("My String")json", [](io::ZeroCopyInputStream* stream) { + EXPECT_THAT(Value::Parse(stream), + IsOkAndHolds(ValueIs("My String"))); + }); +} + +TEST(NonStandard, SingleQuoteString) { + DoLegacy(R"json('My String')json", [=](const Value& value) { + EXPECT_THAT(value, ValueIs("My String")); + }); +} + +TEST(NonStandard, ControlCharsInString) { + DoLegacy("\"\1\2\3\4\5\6\7\b\n\f\r\"", [=](const Value& value) { + EXPECT_THAT(value, ValueIs("\1\2\3\4\5\6\7\b\n\f\r")); + }); +} + +TEST(LexerTest, Latin) { + Do(R"json("Pokémon")json", [](io::ZeroCopyInputStream* stream) { + EXPECT_THAT(Value::Parse(stream), + IsOkAndHolds(ValueIs("Pokémon"))); + }); +} + +TEST(LexerTest, Cjk) { + Do(R"json("施氏食獅史")json", [](io::ZeroCopyInputStream* stream) { + EXPECT_THAT(Value::Parse(stream), + IsOkAndHolds(ValueIs("施氏食獅史"))); + }); +} + +TEST(LexerTest, BrokenString) { + Bad(R"json("broken)json"); + Bad(R"json("broken')json"); + Bad(R"json("broken\")json"); +} + +TEST(NonStandard, BrokenString) { + Bad(R"json('broken)json"); + Bad(R"json('broken")json"); +} + +TEST(LexerTest, BrokenEscape) { + Bad(R"json("\)json"); + Bad(R"json("\a")json"); + Bad(R"json("\u")json"); + Bad(R"json("\u123")json"); + Bad(R"json("\u{1f36f}")json"); + Bad(R"json("\u123$$$")json"); + Bad(R"json("\ud800\udcfg")json"); +} + +void GoodNumber(absl::string_view json, double value) { + Do(json, [value](io::ZeroCopyInputStream* stream) { + EXPECT_THAT(Value::Parse(stream), IsOkAndHolds(ValueIs(value))); + }); +} + +TEST(LexerTest, Zero) { + GoodNumber("0", 0); + GoodNumber("0.0", 0); + GoodNumber("0.000", 0); + GoodNumber("-0", -0.0); + GoodNumber("-0.0", -0.0); + + Bad("00"); + Bad("-00"); +} + +TEST(LexerTest, Integer) { + GoodNumber("123456", 123456); + GoodNumber("-79497823553162768", -79497823553162768); + GoodNumber("11779497823553163264", 11779497823553163264u); + + Bad("0777"); +} + +TEST(LexerTest, Overflow) { + GoodNumber("18446744073709551616", 18446744073709552000.0); + GoodNumber("-18446744073709551616", -18446744073709551616.0); + + Bad("1.89769e308"); + Bad("-1.89769e308"); +} + +TEST(LexerTest, Double) { + GoodNumber("42.5", 42.5); + GoodNumber("42.50", 42.50); + GoodNumber("-1045.235", -1045.235); + GoodNumber("-0.235", -0.235); + + Bad("42."); + Bad("01.3"); + Bad(".5"); + Bad("-.5"); +} + +TEST(LexerTest, Scientific) { + GoodNumber("1.2345e+10", 1.2345e+10); + GoodNumber("1.2345e-10", 1.2345e-10); + GoodNumber("1.2345e10", 1.2345e10); + GoodNumber("1.2345E+10", 1.2345e+10); + GoodNumber("1.2345E-10", 1.2345e-10); + GoodNumber("1.2345E10", 1.2345e10); + GoodNumber("0e0", 0); + GoodNumber("9E9", 9e9); + + Bad("1.e5"); + Bad("-e5"); + Bad("1e"); + Bad("1e-"); + Bad("1e+"); +} + +TEST(LexerTest, EmptyArray) { + Do("[]", [](io::ZeroCopyInputStream* stream) { + EXPECT_THAT(Value::Parse(stream), + IsOkAndHolds(ValueIs(IsEmpty()))); + }); +} + +TEST(LexerTest, PrimitiveArray) { + absl::string_view json = R"json( + [true, false, null, "string"] + )json"; + Do(json, [](io::ZeroCopyInputStream* stream) { + EXPECT_THAT(Value::Parse(stream), + IsOkAndHolds(ValueIs(ElementsAre( + ValueIs(true), // + ValueIs(false), // + ValueIs(_), // + ValueIs("string") // + )))); + }); +} + +TEST(LexerTest, BrokenArray) { + Bad("["); + Bad("[["); + Bad("[true, null}"); +} + +TEST(LexerTest, BrokenStringInArray) { Bad(R"json(["Unterminated])json"); } + +TEST(LexerTest, NestedArray) { + absl::string_view json = R"json( + [ + [22, -127, 45.3, -1056.4, 11779497823553162765], + {"key": true} + ] + )json"; + Do(json, [](io::ZeroCopyInputStream* stream) { + EXPECT_THAT(Value::Parse(stream), + IsOkAndHolds(ValueIs(ElementsAre( + ValueIs(ElementsAre( + ValueIs(22), // + ValueIs(-127), // + ValueIs(45.3), // + ValueIs(-1056.4), // + ValueIs(11779497823553162765u) // + )), + ValueIs( + ElementsAre(Pair("key", ValueIs(true)))))))); + }); +} + +TEST(LexerTest, EmptyObject) { + Do("{}", [](io::ZeroCopyInputStream* stream) { + EXPECT_THAT(Value::Parse(stream), + IsOkAndHolds(ValueIs(IsEmpty()))); + }); +} + +TEST(LexerTest, BrokenObject) { + Bad("{"); + Bad("{{"); + Bad(R"json({"key": true])json"); + Bad(R"json({"key")json"); + Bad(R"json({"key":})json"); +} + +TEST(LexerTest, BrokenStringInObject) { + Bad(R"json({"oops": "Unterminated})json"); +} + +TEST(LexerTest, NonPairInObject) { + Bad("{null}"); + Bad("{true}"); + Bad("{false}"); + Bad("{42}"); + Bad("{[null]}"); + Bad(R"json({{"nest_pas": true}})json"); + Bad(R"json({"missing colon"})json"); +} + +TEST(NonStandard, NonPairInObject) { + Bad("{'missing colon'}"); + Bad("{missing_colon}"); +} + +TEST(LexerTest, WrongCommas) { + Bad("[null null]"); + Bad("[null,, null]"); + Bad(R"json({"a": 0 "b": true})json"); + Bad(R"json({"a": 0,, "b": true})json"); +} + +TEST(NonStandard, Keys) { + DoLegacy(R"json({'s': true})json", [](const Value& value) { + EXPECT_THAT(value, ValueIs( + ElementsAre(Pair("s", ValueIs(true))))); + }); + DoLegacy(R"json({key: null})json", [](const Value& value) { + EXPECT_THAT(value, ValueIs( + ElementsAre(Pair("key", ValueIs(_))))); + }); + DoLegacy(R"json({snake_key: []})json", [](const Value& value) { + EXPECT_THAT(value, ValueIs(ElementsAre(Pair( + "snake_key", ValueIs(IsEmpty()))))); + }); + DoLegacy(R"json({camelKey: {}})json", [](const Value& value) { + EXPECT_THAT(value, ValueIs(ElementsAre(Pair( + "camelKey", ValueIs(IsEmpty()))))); + }); +} + +TEST(NonStandard, KeywordPrefixedKeys) { + DoLegacy(R"json({nullkey: "a"})json", [](const Value& value) { + EXPECT_THAT(value, ValueIs(ElementsAre( + Pair("nullkey", ValueIs("a"))))); + }); + DoLegacy(R"json({truekey: "b"})json", [](const Value& value) { + EXPECT_THAT(value, ValueIs(ElementsAre( + Pair("truekey", ValueIs("b"))))); + }); + DoLegacy(R"json({falsekey: "c"})json", [](const Value& value) { + EXPECT_THAT(value, ValueIs(ElementsAre( + Pair("falsekey", ValueIs("c"))))); + }); +} + +TEST(LexerTest, BadKeys) { + Bad("{null: 0}"); + Bad("{true: 0}"); + Bad("{false: 0}"); + Bad("{lisp-kebab: 0}"); + Bad("{42: true}"); +} + +TEST(LexerTest, NestedObject) { + absl::string_view json = R"json( + { + "t": true, + "f": false, + "n": null, + "s": "a string", + "pi": 22, + "ni": -127, + "pd": 45.3, + "nd": -1056.4, + "pl": 11779497823553162765, + "l": [ [ ] ], + "o": { "key": true } + } + )json"; + Do(json, [](io::ZeroCopyInputStream* stream) { + EXPECT_THAT(Value::Parse(stream), + IsOkAndHolds(ValueIs(ElementsAre( + Pair("t", ValueIs(true)), // + Pair("f", ValueIs(false)), // + Pair("n", ValueIs(_)), // + Pair("s", ValueIs("a string")), // + Pair("pi", ValueIs(22)), // + Pair("ni", ValueIs(-127)), // + Pair("pd", ValueIs(45.3)), // + Pair("nd", ValueIs(-1056.4)), // + Pair("pl", ValueIs(11779497823553162765u)), // + Pair("l", ValueIs(ElementsAre( + ValueIs(IsEmpty())))), // + Pair("o", ValueIs(ElementsAre( + Pair("key", ValueIs(true))))) // + )))); + }); +} + +TEST(LexerTest, RejectNonUtf8) { + absl::string_view json = R"json( + { "address": x"施氏食獅史" } + )json"; + Bad(absl::StrReplaceAll(json, {{"x", "\xff"}})); +} + +TEST(LexerTest, RejectNonUtf8String) { + absl::string_view json = R"json( + { "address": "施氏x食獅史" } + )json"; + Bad(absl::StrReplaceAll(json, {{"x", "\xff"}})); +} + +TEST(LexerTest, RejectNonUtf8Prefix) { Bad("\xff{}"); } + +TEST(LexerTest, SurrogateEscape) { + absl::string_view json = R"json( + [ "\ud83d\udc08\u200D\u2b1B\ud83d\uDdA4" ] + )json"; + Do(json, [](io::ZeroCopyInputStream* stream) { + EXPECT_THAT(Value::Parse(stream), + IsOkAndHolds(ValueIs( + ElementsAre(ValueIs("🐈‍⬛🖤"))))); + }); +} + +TEST(LexerTest, InvalidCodePoint) { Bad(R"json(["\ude36"])json"); } + +TEST(LexerTest, LonelyHighSurrogate) { + Bad(R"json(["\ud83d"])json"); + Bad(R"json(["\ud83d|trailing"])json"); + Bad(R"json(["\ud83d\ude--"])json"); + Bad(R"json(["\ud83d\ud83d"])json"); +} + +TEST(LexerTest, AsciiEscape) { + absl::string_view json = R"json( + ["\b", "\ning", "test\f", "\r\t", "test\\\"\/ing"] + )json"; + Do(json, [](io::ZeroCopyInputStream* stream) { + EXPECT_THAT(Value::Parse(stream), + IsOkAndHolds(ValueIs(ElementsAre( + ValueIs("\b"), // + ValueIs("\ning"), // + ValueIs("test\f"), // + ValueIs("\r\t"), // + ValueIs("test\\\"/ing") // + )))); + }); +} + +TEST(NonStandard, AsciiEscape) { + DoLegacy(R"json(["\'", '\''])json", [](const Value& value) { + EXPECT_THAT(value, + ValueIs(ElementsAre(ValueIs("'"), // + ValueIs("'") // + ))); + }); +} + +TEST(NonStandard, TrailingCommas) { + DoLegacy(R"json({"foo": 42,})json", [](const Value& value) { + EXPECT_THAT(value, ValueIs( + ElementsAre(Pair("foo", ValueIs(42))))); + }); + DoLegacy(R"json({"foo": [42,],})json", [](const Value& value) { + EXPECT_THAT( + value, + ValueIs(ElementsAre(Pair( + "foo", ValueIs(ElementsAre(ValueIs(42))))))); + }); + DoLegacy(R"json([42,])json", [](const Value& value) { + EXPECT_THAT(value, ValueIs(ElementsAre(ValueIs(42)))); + }); + DoLegacy(R"json([{},])json", [](const Value& value) { + EXPECT_THAT(value, ValueIs( + ElementsAre(ValueIs(IsEmpty())))); + }); +} + +// These strings are enormous; so that the test actually finishes in a +// reasonable time, we skip using Do(). + +TEST(LexerTest, ArrayRecursion) { + std::string ok = std::string(ParseOptions::kDefaultDepth, '[') + + std::string(ParseOptions::kDefaultDepth, ']'); + + { + io::ArrayInputStream stream(ok.data(), static_cast(ok.size())); + auto value = Value::Parse(&stream); + ASSERT_OK(value); + + Value* v = &*value; + for (int i = 0; i < ParseOptions::kDefaultDepth - 1; ++i) { + ASSERT_THAT(*v, ValueIs(SizeIs(1))); + v = &absl::get(v->value)[0]; + } + ASSERT_THAT(*v, ValueIs(IsEmpty())); + } + + { + std::string evil = absl::StrFormat("[%s]", ok); + io::ArrayInputStream stream(evil.data(), static_cast(evil.size())); + ASSERT_THAT(Value::Parse(&stream), + StatusIs(absl::StatusCode::kInvalidArgument)); + } +} + +TEST(LexerTest, ObjectRecursion) { + std::string ok; + for (int i = 0; i < ParseOptions::kDefaultDepth - 1; ++i) { + absl::StrAppend(&ok, "{\"k\":"); + } + absl::StrAppend(&ok, "{"); + ok += std::string(ParseOptions::kDefaultDepth, '}'); + + { + io::ArrayInputStream stream(ok.data(), static_cast(ok.size())); + auto value = Value::Parse(&stream); + ASSERT_OK(value); + + Value* v = &*value; + for (int i = 0; i < ParseOptions::kDefaultDepth - 1; ++i) { + ASSERT_THAT(*v, ValueIs(ElementsAre(Pair("k", _)))); + v = &absl::get(v->value)[0].second; + } + ASSERT_THAT(*v, ValueIs(IsEmpty())); + } + { + std::string evil = absl::StrFormat("{\"k\":%s}", ok); + io::ArrayInputStream stream(evil.data(), static_cast(evil.size())); + ASSERT_THAT(Value::Parse(&stream), + StatusIs(absl::StatusCode::kInvalidArgument)); + } +} +} // namespace +} // namespace json_internal +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/json/internal/message_path.cc similarity index 66% rename from src/google/protobuf/compiler/objectivec/objectivec_helpers.h rename to src/google/protobuf/json/internal/message_path.cc index 9c61dfa57b..f3a41c1558 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h +++ b/src/google/protobuf/json/internal/message_path.cc @@ -28,30 +28,40 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Helper functions for generating ObjectiveC code. +#include "google/protobuf/json/internal/message_path.h" -#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__ -#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__ +#include -#include "google/protobuf/compiler/objectivec/names.h" +#include "absl/strings/str_cat.h" -// clang-format off +// Must be included last. #include "google/protobuf/port_def.inc" -// clang-format on namespace google { namespace protobuf { -namespace compiler { -namespace objectivec { +namespace json_internal { +void MessagePath::Describe(std::string& out) const { + absl::StrAppend(&out, components_.front().type_name); + if (components_.size() == 1) { + return; + } -// TODO(thomasvl) Move internal helpers in names.h back to here. Currently -// the dependencies are too interwoven to easily split up. + absl::StrAppend(&out, " @ "); + for (size_t i = 1; i < components_.size(); ++i) { + absl::StrAppend(&out, i == 1 ? "" : ".", components_[i].field_name); + if (components_[i].repeated_index >= 0) { + absl::StrAppend(&out, "[", components_[i].repeated_index, "]"); + } + } + absl::string_view kind_name = + FieldDescriptor::TypeName(components_.back().type); + absl::StrAppend(&out, ": ", kind_name); -} // namespace objectivec -} // namespace compiler + absl::string_view type_name = components_.back().type_name; + if (!type_name.empty()) { + absl::StrAppend(&out, " ", type_name); + } +} +} // namespace json_internal } // namespace protobuf } // namespace google - -#include "google/protobuf/port_undef.inc" - -#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__ diff --git a/src/google/protobuf/util/internal/object_source.h b/src/google/protobuf/json/internal/message_path.h similarity index 52% rename from src/google/protobuf/util/internal/object_source.h rename to src/google/protobuf/json/internal/message_path.h index 2538314859..b1a3f9f5b2 100644 --- a/src/google/protobuf/util/internal/object_source.h +++ b/src/google/protobuf/json/internal/message_path.h @@ -28,56 +28,57 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_SOURCE_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_SOURCE_H__ - -#include "absl/status/status.h" -#include "absl/strings/string_view.h" -#include "google/protobuf/port.h" +#ifndef GOOGLE_PROTOBUF_JSON_INTERNAL_MESSAGE_PATH_H__ +#define GOOGLE_PROTOBUF_JSON_INTERNAL_MESSAGE_PATH_H__ +#include +#include -// Must be included last. -#include "google/protobuf/port_def.inc" +#include "absl/cleanup/cleanup.h" +#include "absl/strings/string_view.h" +#include "google/protobuf/descriptor.h" namespace google { namespace protobuf { -namespace util { -namespace converter { - -class ObjectWriter; - -// An ObjectSource is anything that can write to an ObjectWriter. -// Implementation of this interface typically provide constructors or -// factory methods to create an instance based on some source data, for -// example, a character stream, or protobuf. -// -// Derived classes could be thread-unsafe. -class PROTOBUF_EXPORT ObjectSource { +namespace json_internal { +// A path in a Protobuf message, annotated specifically for producing nice +// errors. +class MessagePath { public: - ObjectSource(const ObjectSource&) = delete; - ObjectSource& operator=(const ObjectSource&) = delete; - virtual ~ObjectSource() {} + explicit MessagePath(absl::string_view message_root) + : components_( + {Component{FieldDescriptor::TYPE_MESSAGE, message_root, "", -1}}) {} - // Writes to the ObjectWriter - virtual absl::Status WriteTo(ObjectWriter* ow) const { - return NamedWriteTo("", ow); + // Pushes a new field name, along with an optional type name if it is + // a message or enum. + // + // Returns an RAII object that will pop the field component on scope exit. + auto Push(absl::string_view field_name, FieldDescriptor::Type type, + absl::string_view type_name = "") { + // -1 makes it so the first call to NextRepeated makes the index 0. + components_.push_back(Component{type, type_name, field_name, -1}); + return absl::MakeCleanup([this] { components_.pop_back(); }); } - // Writes to the ObjectWriter with a custom name for the message. - // This is useful when you chain ObjectSource together by embedding one - // within another. - virtual absl::Status NamedWriteTo(absl::string_view name, - ObjectWriter* ow) const = 0; + // Increments the index of this field, indicating it is a repeated field. + // + // The first time this is called, the field will be marked as repeated and + // the index will become 0. + void NextRepeated() { ++components_.back().repeated_index; } - protected: - ObjectSource() {} -}; + // Appends a description of the current state of the path to `out`. + void Describe(std::string& out) const; -} // namespace converter -} // namespace util + private: + struct Component { + FieldDescriptor::Type type; + absl::string_view type_name, field_name; + int32_t repeated_index; + }; + std::vector components_; +}; +} // namespace json_internal } // namespace protobuf } // namespace google -#include "google/protobuf/port_undef.inc" - -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_SOURCE_H__ +#endif // GOOGLE_PROTOBUF_JSON_INTERNAL_MESSAGE_PATH_H__ diff --git a/src/google/protobuf/json/internal/parser.cc b/src/google/protobuf/json/internal/parser.cc new file mode 100644 index 0000000000..6655aae492 --- /dev/null +++ b/src/google/protobuf/json/internal/parser.cc @@ -0,0 +1,1374 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/json/internal/parser.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "google/protobuf/type.pb.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/dynamic_message.h" +#include "google/protobuf/message.h" +#include "absl/base/attributes.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/ascii.h" +#include "absl/strings/escaping.h" +#include "absl/strings/match.h" +#include "absl/strings/numbers.h" +#include "absl/strings/str_format.h" +#include "absl/strings/str_split.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "absl/types/span.h" +#include "google/protobuf/io/zero_copy_sink.h" +#include "google/protobuf/io/zero_copy_stream.h" +#include "google/protobuf/io/zero_copy_stream_impl_lite.h" +#include "google/protobuf/json/internal/descriptor_traits.h" +#include "google/protobuf/json/internal/lexer.h" +#include "google/protobuf/json/internal/parser_traits.h" +#include "google/protobuf/util/type_resolver.h" +#include "google/protobuf/stubs/status_macros.h" + +// Must be included last. +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace json_internal { +namespace { +// This file contains code that drives a JsonLexer to visit a JSON document and +// convert it into some form of proto. +// +// This semantic layer is duplicated: proto2-ish code can deserialize directly +// into a message, wheras proto3-ish code deserializes into a byte stream, using +// TypeResolvers instead of Descriptors. +// +// The parsing code is templated over which of these two reflection + output +// combinations is used. The traits types that collect the per-instantiation +// functionality can be found in json_util2_parser_traits-inl.h. + +// This table maps an unsigned `char` value, intepreted as an ASCII character, +// to a corresponding value in the base64 alphabet (both traditional and +// "web-safe" characters are included). +// +// If a character is not valid base64, it maps to -1; this is used by the bit +// operations that assemble a base64-encoded word to determine if an error +// occured, by checking the sign bit. +constexpr signed char kBase64Table[256] = { + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, 62 /*+*/, -1, 62 /*-*/, -1, 63 /*/ */, 52 /*0*/, + 53 /*1*/, 54 /*2*/, 55 /*3*/, 56 /*4*/, 57 /*5*/, 58 /*6*/, 59 /*7*/, + 60 /*8*/, 61 /*9*/, -1, -1, -1, -1, -1, + -1, -1, 0 /*A*/, 1 /*B*/, 2 /*C*/, 3 /*D*/, 4 /*E*/, + 5 /*F*/, 6 /*G*/, 07 /*H*/, 8 /*I*/, 9 /*J*/, 10 /*K*/, 11 /*L*/, + 12 /*M*/, 13 /*N*/, 14 /*O*/, 15 /*P*/, 16 /*Q*/, 17 /*R*/, 18 /*S*/, + 19 /*T*/, 20 /*U*/, 21 /*V*/, 22 /*W*/, 23 /*X*/, 24 /*Y*/, 25 /*Z*/, + -1, -1, -1, -1, 63 /*_*/, -1, 26 /*a*/, + 27 /*b*/, 28 /*c*/, 29 /*d*/, 30 /*e*/, 31 /*f*/, 32 /*g*/, 33 /*h*/, + 34 /*i*/, 35 /*j*/, 36 /*k*/, 37 /*l*/, 38 /*m*/, 39 /*n*/, 40 /*o*/, + 41 /*p*/, 42 /*q*/, 43 /*r*/, 44 /*s*/, 45 /*t*/, 46 /*u*/, 47 /*v*/, + 48 /*w*/, 49 /*x*/, 50 /*y*/, 51 /*z*/, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1}; + +uint32_t Base64Lookup(char c) { + // Sign-extend return value so high bit will be set on any unexpected char. + return static_cast(kBase64Table[static_cast(c)]); +} + +// Decodes `base64` in-place, shrinking the length as appropriate. +absl::StatusOr> DecodeBase64InPlace(absl::Span base64) { + // We decode in place. This is safe because this is a new buffer (not + // aliasing the input) and because base64 decoding shrinks 4 bytes into 3. + char* out = base64.data(); + const char* ptr = base64.data(); + const char* end = ptr + base64.size(); + const char* end4 = ptr + (base64.size() & ~3u); + + for (; ptr < end4; ptr += 4, out += 3) { + auto val = Base64Lookup(ptr[0]) << 18 | Base64Lookup(ptr[1]) << 12 | + Base64Lookup(ptr[2]) << 6 | Base64Lookup(ptr[3]) << 0; + + if (static_cast(val) < 0) { + // Junk chars or padding. Remove trailing padding, if any. + if (end - ptr == 4 && ptr[3] == '=') { + if (ptr[2] == '=') { + end -= 2; + } else { + end -= 1; + } + } + break; + } + + out[0] = val >> 16; + out[1] = (val >> 8) & 0xff; + out[2] = val & 0xff; + } + + if (ptr < end) { + uint32_t val = ~0u; + switch (end - ptr) { + case 2: + val = Base64Lookup(ptr[0]) << 18 | Base64Lookup(ptr[1]) << 12; + out[0] = val >> 16; + out += 1; + break; + case 3: + val = Base64Lookup(ptr[0]) << 18 | Base64Lookup(ptr[1]) << 12 | + Base64Lookup(ptr[2]) << 6; + out[0] = val >> 16; + out[1] = (val >> 8) & 0xff; + out += 2; + break; + } + + if (static_cast(val) < 0) { + return absl::InvalidArgumentError("corrupt base64"); + } + } + + return absl::Span(base64.data(), + static_cast(out - base64.data())); +} + +template +absl::StatusOr> ParseIntInner(JsonLexer& lex, double lo, + double hi) { + absl::StatusOr kind = lex.PeekKind(); + RETURN_IF_ERROR(kind.status()); + + LocationWith n; + switch (*kind) { + case JsonLexer::kNum: { + absl::StatusOr> x = lex.ParseRawNumber(); + RETURN_IF_ERROR(x.status()); + n.loc = x->loc; + if (absl::SimpleAtoi(x->value.AsView(), &n.value)) { + break; + } + + double d; + if (!absl::SimpleAtod(x->value.AsView(), &d) || !std::isfinite(d)) { + return x->loc.Invalid( + absl::StrFormat("invalid number: '%s'", x->value.AsView())); + } + + // Conversion overflow here would be UB. + if (lo > d || d > hi) { + return lex.Invalid("JSON number out of range for int"); + } + n.value = static_cast(d); + if (d - static_cast(n.value) != 0) { + return lex.Invalid( + "expected integer, but JSON number had fractional part"); + } + break; + } + case JsonLexer::kStr: { + absl::StatusOr> str = lex.ParseUtf8(); + RETURN_IF_ERROR(str.status()); + // SimpleAtoi will ignore leading and trailing whitespace, so we need + // to check for it outselves. + for (char c : str->value.AsView()) { + if (absl::ascii_isspace(c)) { + return lex.Invalid("non-number characters in quoted number"); + } + } + if (!absl::SimpleAtoi(str->value.AsView(), &n.value)) { + return str->loc.Invalid("non-number characters in quoted number"); + } + n.loc = str->loc; + break; + } + default: + return lex.Invalid("expected number or string"); + } + + return n; +} + +template +absl::StatusOr ParseInt(JsonLexer& lex, Field field) { + absl::StatusOr> n = + ParseIntInner(lex, -9007199254740992.0, 9007199254740992.0); + RETURN_IF_ERROR(n.status()); + + if (Traits::Is32Bit(field)) { + if (std::numeric_limits::min() > n->value || + n->value > std::numeric_limits::max()) { + return n->loc.Invalid("integer out of range"); + } + } + + return n->value; +} + +template +absl::StatusOr ParseUInt(JsonLexer& lex, Field field) { + absl::StatusOr> n = + ParseIntInner(lex, 0, 18014398509481984.0); + RETURN_IF_ERROR(n.status()); + + if (Traits::Is32Bit(field)) { + if (n->value > std::numeric_limits::max()) { + return n->loc.Invalid("integer out of range"); + } + } + + return n->value; +} + +template +absl::StatusOr ParseFp(JsonLexer& lex, Field field) { + absl::StatusOr kind = lex.PeekKind(); + RETURN_IF_ERROR(kind.status()); + + double n; + switch (*kind) { + case JsonLexer::kNum: { + absl::StatusOr> d = lex.ParseNumber(); + RETURN_IF_ERROR(d.status()); + n = d->value; + break; + } + case JsonLexer::kStr: { + absl::StatusOr> str = lex.ParseUtf8(); + RETURN_IF_ERROR(str.status()); + + if (str->value == "NaN") { + n = NAN; + } else if (str->value == "Infinity") { + n = INFINITY; + } else if (str->value == "-Infinity") { + n = -INFINITY; + } else if (!absl::SimpleAtod(str->value.AsView(), &n)) { + return str->loc.Invalid("non-number characters in quoted number"); + } + break; + } + default: + return lex.Invalid("expected number or string"); + } + + if (Traits::Is32Bit(field)) { + // Detect out-of-range 32-bit floats by seeing whether the conversion result + // is still finite. Finite extreme values may have textual representations + // that parse to 64-bit values outside the 32-bit range, but which are + // closer to the 32-bit extreme than to the "next value with the same + // precision". + if (std::isfinite(n) && !std::isfinite(static_cast(n))) { + return lex.Invalid("float out of range"); + } + } + + return n; +} + +template +absl::StatusOr ParseStrOrBytes(JsonLexer& lex, + Field field) { + absl::StatusOr> str = lex.ParseUtf8(); + RETURN_IF_ERROR(str.status()); + + if (Traits::FieldType(field) == FieldDescriptor::TYPE_BYTES) { + std::string& b64 = str->value.ToString(); + absl::StatusOr> decoded = + DecodeBase64InPlace(absl::MakeSpan(&b64[0], b64.size())); + if (!decoded.ok()) { + return str->loc.Invalid(decoded.status().message()); + } + b64.resize(decoded->size()); + } + + return std::move(str->value.ToString()); +} + +template +absl::StatusOr> ParseEnumFromStr(JsonLexer& lex, + MaybeOwnedString& str, + Field field) { + absl::StatusOr value = Traits::EnumNumberByName( + field, str.AsView(), lex.options().case_insensitive_enum_parsing); + if (value.ok()) { + return absl::optional(*value); + } + + int32_t i; + if (absl::SimpleAtoi(str.AsView(), &i)) { + return absl::optional(i); + } else if (lex.options().ignore_unknown_fields) { + return {absl::nullopt}; + } + + return value.status(); +} + +// Parses an enum; can return nullopt if a quoted enumerator that we don't +// know about is received and `ignore_unknown_fields` is set. +template +absl::StatusOr> ParseEnum(JsonLexer& lex, + Field field) { + absl::StatusOr kind = lex.PeekKind(); + RETURN_IF_ERROR(kind.status()); + + int32_t n = 0; + switch (*kind) { + case JsonLexer::kStr: { + absl::StatusOr> str = lex.ParseUtf8(); + RETURN_IF_ERROR(str.status()); + + auto e = ParseEnumFromStr(lex, str->value, field); + RETURN_IF_ERROR(e.status()); + if (!e->has_value()) { + return {absl::nullopt}; + } + n = **e; + break; + } + case JsonLexer::kNum: + return ParseInt(lex, field); + default: + return lex.Invalid("expected number or string"); + } + + return n; +} + +// Mutually recursive with functions that follow. +template +absl::Status ParseMessage(JsonLexer& lex, const Desc& desc, + Msg& msg, bool any_reparse); +template +absl::Status ParseField(JsonLexer& lex, const Desc& desc, + absl::string_view name, Msg& msg); + +template +absl::Status ParseSingular(JsonLexer& lex, Field field, + Msg& msg) { + auto field_type = Traits::FieldType(field); + if (lex.Peek(JsonLexer::kNull)) { + auto message_type = ClassifyMessage(Traits::FieldTypeName(field)); + switch (field_type) { + case FieldDescriptor::TYPE_ENUM: + if (message_type == MessageType::kNull) { + Traits::SetEnum(field, msg, 0); + } + break; + case FieldDescriptor::TYPE_MESSAGE: { + if (message_type == MessageType::kValue) { + return Traits::NewMsg( + field, msg, + [&](const Desc& type, Msg& msg) -> absl::Status { + auto field = Traits::FieldByNumber(type, 1); + GOOGLE_DCHECK(field.has_value()); + RETURN_IF_ERROR(lex.Expect("null")); + Traits::SetEnum(Traits::MustHaveField(type, 1), msg, 0); + return absl::OkStatus(); + }); + } + break; + } + default: + break; + } + return lex.Expect("null"); + } + + switch (field_type) { + case FieldDescriptor::TYPE_FLOAT: { + auto x = ParseFp(lex, field); + RETURN_IF_ERROR(x.status()); + Traits::SetFloat(field, msg, *x); + break; + } + case FieldDescriptor::TYPE_DOUBLE: { + auto x = ParseFp(lex, field); + RETURN_IF_ERROR(x.status()); + Traits::SetDouble(field, msg, *x); + break; + } + + case FieldDescriptor::TYPE_SFIXED64: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_INT64: { + auto x = ParseInt(lex, field); + RETURN_IF_ERROR(x.status()); + Traits::SetInt64(field, msg, *x); + break; + } + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_UINT64: { + auto x = ParseUInt(lex, field); + RETURN_IF_ERROR(x.status()); + Traits::SetUInt64(field, msg, *x); + break; + } + + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_INT32: { + auto x = ParseInt(lex, field); + RETURN_IF_ERROR(x.status()); + Traits::SetInt32(field, msg, static_cast(*x)); + break; + } + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_UINT32: { + auto x = ParseUInt(lex, field); + RETURN_IF_ERROR(x.status()); + Traits::SetUInt32(field, msg, static_cast(*x)); + break; + } + case FieldDescriptor::TYPE_BOOL: { + absl::StatusOr kind = lex.PeekKind(); + RETURN_IF_ERROR(kind.status()); + + switch (*kind) { + case JsonLexer::kTrue: + RETURN_IF_ERROR(lex.Expect("true")); + Traits::SetBool(field, msg, true); + break; + case JsonLexer::kFalse: + RETURN_IF_ERROR(lex.Expect("false")); + Traits::SetBool(field, msg, false); + break; + case JsonLexer::kStr: { + if (!lex.options().allow_legacy_syntax) { + goto bad; + } + + auto x = lex.ParseUtf8(); + RETURN_IF_ERROR(x.status()); + + bool flag; + if (!absl::SimpleAtob(x->value, &flag)) { + // Is this error a lie? Do we accept things otyher than "true" and + // "false" because SimpleAtob does? Absolutely! + return x->loc.Invalid("expected 'true' or 'false'"); + } + Traits::SetBool(field, msg, flag); + + break; + } + bad: + default: + return lex.Invalid("expected 'true' or 'false'"); + } + break; + } + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: { + auto x = ParseStrOrBytes(lex, field); + RETURN_IF_ERROR(x.status()); + Traits::SetString(field, msg, *x); + break; + } + case FieldDescriptor::TYPE_ENUM: { + absl::StatusOr> x = ParseEnum(lex, field); + RETURN_IF_ERROR(x.status()); + + if (x->has_value() || !Traits::IsOptional(field)) { + Traits::SetEnum(field, msg, x->value_or(0)); + } + break; + } + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: { + return Traits::NewMsg( + field, msg, + [&](const Desc& type, Msg& msg) -> absl::Status { + return ParseMessage(lex, type, msg, + /*any_reparse=*/false); + }); + } + default: + return lex.Invalid( + absl::StrCat("unsupported field type: ", Traits::FieldType(field))); + } + + return absl::OkStatus(); +} + +template +absl::Status EmitNull(JsonLexer& lex, Field field, Msg& msg) { + switch (Traits::FieldType(field)) { + case FieldDescriptor::TYPE_FLOAT: + Traits::SetFloat(field, msg, 0); + break; + case FieldDescriptor::TYPE_DOUBLE: + Traits::SetDouble(field, msg, 0); + break; + case FieldDescriptor::TYPE_SFIXED64: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_INT64: + Traits::SetInt64(field, msg, 0); + break; + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_UINT64: + Traits::SetUInt64(field, msg, 0); + break; + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_INT32: + Traits::SetInt32(field, msg, 0); + break; + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_UINT32: + Traits::SetUInt32(field, msg, 0); + break; + case FieldDescriptor::TYPE_BOOL: + Traits::SetBool(field, msg, false); + break; + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: + Traits::SetString(field, msg, ""); + break; + case FieldDescriptor::TYPE_ENUM: + Traits::SetEnum(field, msg, 0); + break; + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: + return Traits::NewMsg(field, msg, + [](const auto&, const auto&) -> absl::Status { + return absl::OkStatus(); + }); + default: + return lex.Invalid( + absl::StrCat("unsupported field type: ", Traits::FieldType(field))); + } + return absl::OkStatus(); +} + +template +absl::Status ParseArray(JsonLexer& lex, Field field, Msg& msg) { + if (lex.Peek(JsonLexer::kNull)) { + return lex.Expect("null"); + } + + return lex.VisitArray([&]() -> absl::Status { + lex.path().NextRepeated(); + MessageType type = ClassifyMessage(Traits::FieldTypeName(field)); + + if (lex.Peek(JsonLexer::kNull)) { + if (type == MessageType::kValue) { + return ParseSingular(lex, field, msg); + } + if (type == MessageType::kNull) { + return ParseSingular(lex, field, msg); + } + + if (lex.options().allow_legacy_syntax) { + RETURN_IF_ERROR(lex.Expect("null")); + return EmitNull(lex, field, msg); + } + return lex.Invalid("null cannot occur inside of repeated fields"); + } + + // Note that this is sufficient to catch when we are inside of a ListValue, + // because a ListValue's sole field is of type Value. Thus, we only need to + // classify cases in which we are inside of an array and parsing messages + // that like looking like arrays. + // + // This will also correctly handle e.g. writing out a ListValue with the + // legacy syntax of `{"values": [[0], [1], [2]]}`, which does not go through + // the custom parser handler. + bool can_flatten = + type != MessageType::kValue && type != MessageType::kList; + if (can_flatten && lex.options().allow_legacy_syntax && + lex.Peek(JsonLexer::kArr)) { + // You read that right. In legacy mode, if we encounter an array within + // an array, we just flatten it as part of the current array! + // + // This DOES NOT apply when parsing a google.protobuf.Value or a + // google.protobuf.ListValue! + return ParseArray(lex, field, msg); + } + return ParseSingular(lex, field, msg); + }); +} + +template +absl::Status ParseMap(JsonLexer& lex, Field field, Msg& msg) { + if (lex.Peek(JsonLexer::kNull)) { + return lex.Expect("null"); + } + + absl::flat_hash_set keys_seen; + return lex.VisitObject( + [&](LocationWith& key) -> absl::Status { + lex.path().NextRepeated(); + auto insert_result = keys_seen.emplace(key.value.AsView()); + if (!insert_result.second) { + return key.loc.Invalid(absl::StrFormat( + "got unexpectedly-repeated repeated map key: '%s'", + key.value.AsView())); + } + return Traits::NewMsg( + field, msg, + [&](const Desc& type, Msg& entry) -> absl::Status { + auto key_field = Traits::KeyField(type); + switch (Traits::FieldType(key_field)) { + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_SFIXED64: { + int64_t n; + if (!absl::SimpleAtoi(key.value.AsView(), &n)) { + return key.loc.Invalid( + "non-number characters in quoted number"); + } + Traits::SetInt64(key_field, entry, n); + break; + } + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_FIXED64: { + uint64_t n; + if (!absl::SimpleAtoi(key.value.AsView(), &n)) { + return key.loc.Invalid( + "non-number characters in quoted number"); + } + Traits::SetUInt64(key_field, entry, n); + break; + } + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_SFIXED32: { + int32_t n; + if (!absl::SimpleAtoi(key.value.AsView(), &n)) { + return key.loc.Invalid( + "non-number characters in quoted number"); + } + Traits::SetInt32(key_field, entry, n); + break; + } + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_FIXED32: { + uint32_t n; + if (!absl::SimpleAtoi(key.value.AsView(), &n)) { + return key.loc.Invalid( + "non-number characters in quoted number"); + } + Traits::SetUInt32(key_field, entry, n); + break; + } + case FieldDescriptor::TYPE_BOOL: { + if (key.value == "true") { + Traits::SetBool(key_field, entry, true); + } else if (key.value == "false") { + Traits::SetBool(key_field, entry, false); + } else { + return key.loc.Invalid(absl::StrFormat( + "expected bool string, got '%s'", key.value.AsView())); + } + break; + } + case FieldDescriptor::TYPE_ENUM: { + MaybeOwnedString key_str = key.value; + auto e = ParseEnumFromStr(lex, key_str, field); + RETURN_IF_ERROR(e.status()); + Traits::SetEnum(key_field, entry, e->value_or(0)); + break; + } + case FieldDescriptor::TYPE_STRING: { + Traits::SetString(key_field, entry, + std::move(key.value.ToString())); + break; + } + default: + return lex.Invalid("unsupported map key type"); + } + + return ParseSingular(lex, Traits::ValueField(type), + entry); + }); + }); +} + +absl::optional TakeTimeDigitsWithSuffixAndAdvance( + absl::string_view& data, int max_digits, absl::string_view end) { + GOOGLE_DCHECK_LE(max_digits, 9); + + uint32_t val = 0; + int limit = max_digits; + while (!data.empty()) { + if (limit-- < 0) { + return absl::nullopt; + } + uint32_t digit = data[0] - '0'; + if (digit >= 10) { + break; + } + + val *= 10; + val += digit; + data = data.substr(1); + } + if (!absl::StartsWith(data, end)) { + return absl::nullopt; + } + + data = data.substr(end.size()); + return val; +} + +absl::optional TakeNanosAndAdvance(absl::string_view& data) { + int32_t frac_secs = 0; + size_t frac_digits = 0; + if (absl::StartsWith(data, ".")) { + for (char c : data.substr(1)) { + if (!absl::ascii_isdigit(c)) { + break; + } + ++frac_digits; + } + auto digits = data.substr(1, frac_digits); + if (frac_digits == 0 || frac_digits > 9 || + !absl::SimpleAtoi(digits, &frac_secs)) { + return absl::nullopt; + } + data = data.substr(frac_digits + 1); + } + for (int i = 0; i < 9 - frac_digits; ++i) { + frac_secs *= 10; + } + return frac_secs; +} + +template +absl::Status ParseTimestamp(JsonLexer& lex, const Desc& desc, + Msg& msg) { + if (lex.Peek(JsonLexer::kNull)) { + return lex.Expect("null"); + } + + absl::StatusOr> str = lex.ParseUtf8(); + RETURN_IF_ERROR(str.status()); + + absl::string_view data = str->value.AsView(); + if (data.size() < 20) { + return str->loc.Invalid("timestamp string too short"); + } + + int64_t secs; + { + /* 1972-01-01T01:00:00 */ + auto year = TakeTimeDigitsWithSuffixAndAdvance(data, 4, "-"); + if (!year.has_value() || *year == 0) { + return str->loc.Invalid("bad year in timestamp"); + } + auto mon = TakeTimeDigitsWithSuffixAndAdvance(data, 2, "-"); + if (!mon.has_value() || *mon == 0) { + return str->loc.Invalid("bad month in timestamp"); + } + auto day = TakeTimeDigitsWithSuffixAndAdvance(data, 2, "T"); + if (!day.has_value() || *day == 0) { + return str->loc.Invalid("bad day in timestamp"); + } + auto hour = TakeTimeDigitsWithSuffixAndAdvance(data, 2, ":"); + if (!hour.has_value()) { + return str->loc.Invalid("bad hours in timestamp"); + } + auto min = TakeTimeDigitsWithSuffixAndAdvance(data, 2, ":"); + if (!min.has_value()) { + return str->loc.Invalid("bad minutes in timestamp"); + } + auto sec = TakeTimeDigitsWithSuffixAndAdvance(data, 2, ""); + if (!sec.has_value()) { + return str->loc.Invalid("bad seconds in timestamp"); + } + + uint32_t m_adj = *mon - 3; // March-based month. + uint32_t carry = m_adj > *mon ? 1 : 0; + + uint32_t year_base = 4800; // Before min year, multiple of 400. + uint32_t y_adj = *year + year_base - carry; + + uint32_t month_days = ((m_adj + carry * 12) * 62719 + 769) / 2048; + uint32_t leap_days = y_adj / 4 - y_adj / 100 + y_adj / 400; + int32_t epoch_days = + y_adj * 365 + leap_days + month_days + (*day - 1) - 2472632; + + secs = int64_t{epoch_days} * 86400 + *hour * 3600 + *min * 60 + *sec; + } + + auto nanos = TakeNanosAndAdvance(data); + if (!nanos.has_value()) { + return str->loc.Invalid("timestamp had bad nanoseconds"); + } + + if (data.empty()) { + return str->loc.Invalid("timestamp missing timezone offset"); + } + + { + // [+-]hh:mm or Z + bool neg = false; + switch (data[0]) { + case '-': + neg = true; + ABSL_FALLTHROUGH_INTENDED; + case '+': { + if (data.size() != 6) { + return str->loc.Invalid("timestamp offset of wrong size."); + } + + data = data.substr(1); + auto hour = TakeTimeDigitsWithSuffixAndAdvance(data, 2, ":"); + auto mins = TakeTimeDigitsWithSuffixAndAdvance(data, 2, ""); + if (!hour.has_value() || !mins.has_value()) { + return str->loc.Invalid("timestamp offset has bad hours and minutes"); + } + + int64_t offset = (*hour * 60 + *mins) * 60; + secs += (neg ? offset : -offset); + break; + } + // Lowercase z is not accepted, per the spec. + case 'Z': + if (data.size() == 1) { + break; + } + ABSL_FALLTHROUGH_INTENDED; + default: + return str->loc.Invalid("bad timezone offset"); + } + } + + Traits::SetInt64(Traits::MustHaveField(desc, 1), msg, secs); + Traits::SetInt32(Traits::MustHaveField(desc, 2), msg, *nanos); + + return absl::OkStatus(); +} + +template +absl::Status ParseDuration(JsonLexer& lex, const Desc& desc, + Msg& msg) { + if (lex.Peek(JsonLexer::kNull)) { + return lex.Expect("null"); + } + + constexpr int64_t kMaxSeconds = int64_t{3652500} * 86400; + + absl::StatusOr> str = lex.ParseUtf8(); + RETURN_IF_ERROR(str.status()); + + size_t int_part_end = 0; + for (char c : str->value.AsView()) { + if (!absl::ascii_isdigit(c) && c != '-') { + break; + } + ++int_part_end; + } + if (int_part_end == 0) { + return str->loc.Invalid("duration must start with an integer"); + } + + absl::string_view sec_digits = str->value.AsView().substr(0, int_part_end); + int64_t secs; + if (!absl::SimpleAtoi(sec_digits, &secs)) { + return str->loc.Invalid("duration had bad seconds"); + } + + if (secs > kMaxSeconds || secs < -kMaxSeconds) { + return str->loc.Invalid("duration out of range"); + } + + absl::string_view rest = str->value.AsView().substr(int_part_end); + auto nanos = TakeNanosAndAdvance(rest); + if (!nanos.has_value()) { + return str->loc.Invalid("duration had bad nanoseconds"); + } + + bool isNegative = (secs < 0) || absl::StartsWith(sec_digits, "-"); + if (isNegative) { + *nanos *= -1; + } + + if (rest != "s") { + return str->loc.Invalid("duration must end with a single 's'"); + } + + Traits::SetInt64(Traits::MustHaveField(desc, 1), msg, secs); + Traits::SetInt32(Traits::MustHaveField(desc, 2), msg, *nanos); + + return absl::OkStatus(); +} + +template +absl::Status ParseFieldMask(JsonLexer& lex, const Desc& desc, + Msg& msg) { + absl::StatusOr> str = lex.ParseUtf8(); + RETURN_IF_ERROR(str.status()); + auto paths = str->value.AsView(); + + // The special case of the empty string is not handled correctly below, + // because StrSplit("", ',') is [""], not []. + if (paths.empty()) { + return absl::OkStatus(); + } + + // google.protobuf.FieldMask has a single field with number 1. + auto paths_field = Traits::MustHaveField(desc, 1); + for (absl::string_view path : absl::StrSplit(paths, ',')) { + std::string snake_path; + // Assume approximately six-letter words, so add one extra space for an + // underscore for every six bytes. + snake_path.reserve(path.size() * 7 / 6); + for (char c : path) { + if (absl::ascii_isdigit(c) || absl::ascii_islower(c) || c == '.') { + snake_path.push_back(c); + } else if (absl::ascii_isupper(c)) { + snake_path.push_back('_'); + snake_path.push_back(absl::ascii_tolower(c)); + } else if (lex.options().allow_legacy_syntax) { + snake_path.push_back(c); + } else { + return str->loc.Invalid("unexpected character in FieldMask"); + } + } + Traits::SetString(paths_field, msg, snake_path); + } + + return absl::OkStatus(); +} + +template +absl::Status ParseAny(JsonLexer& lex, const Desc& desc, + Msg& msg) { + // Buffer an entire object. Because @type can occur anywhere, we're forced + // to do this. + RETURN_IF_ERROR(lex.SkipToToken()); + auto mark = lex.BeginMark(); + + // Search for @type, buffering the entire object along the way so we can + // reparse it. + absl::optional type_url; + RETURN_IF_ERROR(lex.VisitObject( + [&](const LocationWith& key) -> absl::Status { + if (key.value == "@type") { + if (type_url.has_value()) { + return key.loc.Invalid("repeated @type in Any"); + } + + absl::StatusOr> maybe_url = + lex.ParseUtf8(); + RETURN_IF_ERROR(maybe_url.status()); + type_url = std::move(maybe_url)->value; + return absl::OkStatus(); + } + return lex.SkipValue(); + })); + + // Build a new lexer over the skipped object. + absl::string_view any_text = mark.value.UpToUnread(); + io::ArrayInputStream in(any_text.data(), any_text.size()); + // Copying lex.options() is important; it inherits the recursion + // limit. + JsonLexer any_lex(&in, lex.options(), &lex.path(), mark.loc); + + if (!type_url.has_value() && !lex.options().allow_legacy_syntax) { + return mark.loc.Invalid("missing @type in Any"); + } + + if (type_url.has_value()) { + Traits::SetString(Traits::MustHaveField(desc, 1), msg, type_url->AsView()); + return Traits::NewDynamic( + Traits::MustHaveField(desc, 2), type_url->ToString(), msg, + [&](const Desc& desc, Msg& msg) { + auto pop = any_lex.path().Push("", FieldDescriptor::TYPE_MESSAGE, + Traits::TypeName(desc)); + return ParseMessage(any_lex, desc, msg, + /*any_reparse=*/true); + }); + } else { + // Empty {} is accepted in legacy mode. + GOOGLE_DCHECK(lex.options().allow_legacy_syntax); + RETURN_IF_ERROR(any_lex.VisitObject([&](auto&) { + return mark.loc.Invalid( + "in legacy mode, missing @type in Any is only allowed for an empty " + "object"); + })); + return absl::OkStatus(); + } +} + +// These are mutually recursive with ParseValue. +template +absl::Status ParseStructValue(JsonLexer& lex, const Desc& desc, + Msg& msg); +template +absl::Status ParseListValue(JsonLexer& lex, const Desc& desc, + Msg& msg); + +template +absl::Status ParseValue(JsonLexer& lex, const Desc& desc, + Msg& msg) { + auto kind = lex.PeekKind(); + RETURN_IF_ERROR(kind.status()); + // NOTE: The field numbers 1 through 6 are the numbers of the oneof fields + // in google.protobuf.Value. Conformance tests verify the correctness of + // these numbers. + switch (*kind) { + case JsonLexer::kNull: { + auto field = Traits::MustHaveField(desc, 1); + auto pop = + lex.path().Push(Traits::FieldName(field), Traits::FieldType(field), + Traits::FieldTypeName(field)); + + RETURN_IF_ERROR(lex.Expect("null")); + Traits::SetEnum(field, msg, 0); + break; + } + case JsonLexer::kNum: { + auto field = Traits::MustHaveField(desc, 2); + auto pop = + lex.path().Push(Traits::FieldName(field), Traits::FieldType(field), + Traits::FieldTypeName(field)); + + auto number = lex.ParseNumber(); + RETURN_IF_ERROR(number.status()); + Traits::SetDouble(field, msg, number->value); + break; + } + case JsonLexer::kStr: { + auto field = Traits::MustHaveField(desc, 3); + auto pop = + lex.path().Push(Traits::FieldName(field), Traits::FieldType(field), + Traits::FieldTypeName(field)); + + auto str = lex.ParseUtf8(); + RETURN_IF_ERROR(str.status()); + Traits::SetString(field, msg, std::move(str->value.ToString())); + break; + } + case JsonLexer::kFalse: + case JsonLexer::kTrue: { + auto field = Traits::MustHaveField(desc, 4); + auto pop = + lex.path().Push(Traits::FieldName(field), Traits::FieldType(field), + Traits::FieldTypeName(field)); + + // "Quoted" bools, including non-standard Abseil Atob bools, are not + // supported, because all strings are treated as genuine JSON strings. + if (*kind == JsonLexer::kTrue) { + RETURN_IF_ERROR(lex.Expect("true")); + Traits::SetBool(field, msg, true); + } else { + RETURN_IF_ERROR(lex.Expect("false")); + Traits::SetBool(field, msg, false); + } + break; + } + case JsonLexer::kObj: { + auto field = Traits::MustHaveField(desc, 5); + auto pop = + lex.path().Push(Traits::FieldName(field), Traits::FieldType(field), + Traits::FieldTypeName(field)); + + return Traits::NewMsg(field, msg, [&](auto& desc, auto& msg) { + return ParseStructValue(lex, desc, msg); + }); + } + case JsonLexer::kArr: { + auto field = Traits::MustHaveField(desc, 6); + auto pop = + lex.path().Push(Traits::FieldName(field), Traits::FieldType(field), + Traits::FieldTypeName(field)); + + return Traits::NewMsg(field, msg, [&](auto& desc, auto& msg) { + return ParseListValue(lex, desc, msg); + }); + } + } + + return absl::OkStatus(); +} + +template +absl::Status ParseStructValue(JsonLexer& lex, const Desc& desc, + Msg& msg) { + auto entry_field = Traits::MustHaveField(desc, 1); + auto pop = lex.path().Push("", FieldDescriptor::TYPE_MESSAGE, + Traits::FieldTypeName(entry_field)); + + // Structs are always cleared even if set to {}. + Traits::RecordAsSeen(entry_field, msg); + + // Parsing a map does the right thing: Struct has a single map field; keys are correctly parsed as strings, and the values + // recurse into ParseMessage, which will be routed into ParseValue. This + // results in some extra overhead, but performance is not what we're going + // for here. + return ParseMap(lex, entry_field, msg); +} + +template +absl::Status ParseListValue(JsonLexer& lex, const Desc& desc, + Msg& msg) { + auto entry_field = Traits::MustHaveField(desc, 1); + auto pop = lex.path().Push("", FieldDescriptor::TYPE_MESSAGE, + Traits::FieldTypeName(entry_field)); + + // ListValues are always cleared even if set to []. + Traits::RecordAsSeen(entry_field, msg); + // Parsing an array does the right thing: see the analogous comment in + // ParseStructValue. + return ParseArray(lex, entry_field, msg); +} + +template +absl::Status ParseField(JsonLexer& lex, const Desc& desc, + absl::string_view name, Msg& msg) { + absl::optional> field; + if (absl::StartsWith(name, "[") && absl::EndsWith(name, "]")) { + absl::string_view extn_name = name.substr(1, name.size() - 2); + field = Traits::ExtensionByName(desc, extn_name); + } else { + field = Traits::FieldByName(desc, name); + } + + if (!field.has_value()) { + if (!lex.options().ignore_unknown_fields) { + return lex.Invalid(absl::StrFormat("no such field: '%s'", name)); + } + return lex.SkipValue(); + } + + auto pop = lex.path().Push(name, Traits::FieldType(*field), + Traits::FieldTypeName(*field)); + + if (Traits::HasParsed( + *field, msg, + /*allow_repeated_non_oneof=*/lex.options().allow_legacy_syntax) && + !lex.Peek(JsonLexer::kNull)) { + return lex.Invalid(absl::StrFormat( + "'%s' has already been set (either directly or as part of a oneof)", + name)); + } + + if (Traits::IsMap(*field)) { + return ParseMap(lex, *field, msg); + } + + if (Traits::IsRepeated(*field)) { + if (lex.options().allow_legacy_syntax && !lex.Peek(JsonLexer::kArr)) { + // The original ESF parser premits a single element in place of an array + // thereof. + return ParseSingular(lex, *field, msg); + } + return ParseArray(lex, *field, msg); + } + + return ParseSingular(lex, *field, msg); +} + +template +absl::Status ParseMessage(JsonLexer& lex, const Desc& desc, + Msg& msg, bool any_reparse) { + MessageType type = ClassifyMessage(Traits::TypeName(desc)); + if (!any_reparse) { + switch (type) { + case MessageType::kAny: + return ParseAny(lex, desc, msg); + case MessageType::kValue: + return ParseValue(lex, desc, msg); + case MessageType::kStruct: + return ParseStructValue(lex, desc, msg); + default: + break; + } + // For some types, the ESF parser permits parsing the "non-special" version. + // It is not clear if this counts as out-of-spec, but we're treating it as + // such. + bool is_upcoming_object = lex.Peek(JsonLexer::kObj); + if (!(is_upcoming_object && lex.options().allow_legacy_syntax)) { + switch (type) { + case MessageType::kList: + return ParseListValue(lex, desc, msg); + case MessageType::kWrapper: { + return ParseSingular(lex, Traits::MustHaveField(desc, 1), + msg); + } + case MessageType::kTimestamp: + return ParseTimestamp(lex, desc, msg); + case MessageType::kDuration: + return ParseDuration(lex, desc, msg); + case MessageType::kFieldMask: + return ParseFieldMask(lex, desc, msg); + default: + break; + } + } + } + + return lex.VisitObject( + [&](LocationWith& name) -> absl::Status { + // If this is a well-known type, we expect its contents to be inside + // of a JSON field named "value". + if (any_reparse) { + if (name.value == "@type") { + RETURN_IF_ERROR(lex.SkipValue()); + return absl::OkStatus(); + } + if (type != MessageType::kNotWellKnown) { + if (name.value != "value") { + return lex.Invalid( + "fields in a well-known-typed Any must be @type or value"); + } + // Parse the upcoming value as the message itself. This is *not* + // an Any reparse because we do not expect to see @type in the + // upcoming value. + return ParseMessage(lex, desc, msg, + /*any_reparse=*/false); + } + } + + return ParseField(lex, desc, name.value.AsView(), msg); + }); +} +} // namespace + +absl::Status JsonStringToMessage(absl::string_view input, Message* message, + json_internal::ParseOptions options) { + MessagePath path(message->GetDescriptor()->full_name()); + PROTOBUF_DLOG(INFO) << "json2/input: " << absl::CHexEscape(input); + io::ArrayInputStream in(input.data(), input.size()); + JsonLexer lex(&in, options, &path); + + ParseProto2Descriptor::Msg msg(message); + absl::Status s = + ParseMessage(lex, *message->GetDescriptor(), msg, + /*any_reparse=*/false); + if (s.ok() && !lex.AtEof()) { + s = absl::InvalidArgumentError( + "extraneous characters after end of JSON object"); + } + + PROTOBUF_DLOG(INFO) << "json2/status: " << s; + PROTOBUF_DLOG(INFO) << "json2/output: " << message->DebugString(); + + return s; +} + +absl::Status JsonToBinaryStream(google::protobuf::util::TypeResolver* resolver, + const std::string& type_url, + io::ZeroCopyInputStream* json_input, + io::ZeroCopyOutputStream* binary_output, + json_internal::ParseOptions options) { + // NOTE: Most of the contortions in this function are to allow for capture of + // input and output of the parser in GOOGLE_DLOG mode. Destruction order is very + // critical in this function, because io::ZeroCopy*Stream types usually only + // flush on destruction. + + // For GOOGLE_DLOG, we would like to print out the input and output, which requires + // buffering both instead of doing "zero copy". This block, and the one at + // the end of the function, set up and tear down interception of the input + // and output streams. + std::string copy; + std::string out; + absl::optional tee_input; + absl::optional tee_output; + if (PROTOBUF_DEBUG) { + const void* data; + int len; + while (json_input->Next(&data, &len)) { + copy.resize(copy.size() + len); + std::memcpy(©[copy.size() - len], data, len); + } + tee_input.emplace(copy.data(), copy.size()); + tee_output.emplace(&out); + } + + PROTOBUF_DLOG(INFO) << "json2/input: " << absl::CHexEscape(copy); + + // This scope forces the CodedOutputStream inside of `msg` to flush before we + // possibly handle logging the binary protobuf output. + absl::Status s; + { + MessagePath path(type_url); + JsonLexer lex(tee_input.has_value() ? &*tee_input : json_input, options, + &path); + Msg msg(tee_output.has_value() ? &*tee_output + : binary_output); + + ResolverPool pool(resolver); + auto desc = pool.FindMessage(type_url); + RETURN_IF_ERROR(desc.status()); + + s = ParseMessage(lex, **desc, msg, /*any_reparse=*/false); + if (s.ok() && !lex.AtEof()) { + s = absl::InvalidArgumentError( + "extraneous characters after end of JSON object"); + } + } + + if (PROTOBUF_DEBUG) { + tee_output.reset(); // Flush the output stream. + io::zc_sink_internal::ZeroCopyStreamByteSink(binary_output) + .Append(out.data(), out.size()); + } + + PROTOBUF_DLOG(INFO) << "json2/status: " << s; + PROTOBUF_DLOG(INFO) << "json2/output: " << absl::BytesToHexString(out); + return s; +} +} // namespace json_internal +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/util/internal/mock_error_listener.h b/src/google/protobuf/json/internal/parser.h similarity index 62% rename from src/google/protobuf/util/internal/mock_error_listener.h rename to src/google/protobuf/json/internal/parser.h index b04de6ff09..79ba29a249 100644 --- a/src/google/protobuf/util/internal/mock_error_listener.h +++ b/src/google/protobuf/json/internal/parser.h @@ -28,41 +28,32 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_MOCK_ERROR_LISTENER_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_MOCK_ERROR_LISTENER_H__ +#ifndef GOOGLE_PROTOBUF_JSON_INTERNAL_PARSER_H__ +#define GOOGLE_PROTOBUF_JSON_INTERNAL_PARSER_H__ -#include +#include + +#include "google/protobuf/message.h" #include "absl/strings/string_view.h" -#include "google/protobuf/util/internal/error_listener.h" -#include "google/protobuf/util/internal/location_tracker.h" +#include "google/protobuf/json/internal/lexer.h" +#include "google/protobuf/util/type_resolver.h" namespace google { namespace protobuf { -namespace util { -namespace converter { - -class MockErrorListener : public ErrorListener { - public: - MockErrorListener() {} - ~MockErrorListener() override {} - - MOCK_METHOD(void, InvalidName, - (const LocationTrackerInterface& loc, - absl::string_view unknown_name, absl::string_view message), - (override)); - MOCK_METHOD(void, InvalidValue, - (const LocationTrackerInterface& loc, absl::string_view type_name, - absl::string_view value), - (override)); - MOCK_METHOD(void, MissingField, - (const LocationTrackerInterface& loc, - absl::string_view missing_name), - (override)); -}; - -} // namespace converter -} // namespace util +namespace json_internal { +// Internal version of google::protobuf::util::JsonStringToMessage; see json_util.h for +// details. +absl::Status JsonStringToMessage(absl::string_view input, Message* message, + json_internal::ParseOptions options); +// Internal version of google::protobuf::util::JsonToBinaryStream; see json_util.h for +// details. +absl::Status JsonToBinaryStream(google::protobuf::util::TypeResolver* resolver, + const std::string& type_url, + io::ZeroCopyInputStream* json_input, + io::ZeroCopyOutputStream* binary_output, + json_internal::ParseOptions options); +} // namespace json_internal } // namespace protobuf } // namespace google -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_MOCK_ERROR_LISTENER_H__ +#endif // GOOGLE_PROTOBUF_JSON_INTERNAL_PARSER_H__ diff --git a/src/google/protobuf/json/internal/parser_traits.h b/src/google/protobuf/json/internal/parser_traits.h new file mode 100644 index 0000000000..6bc88736b1 --- /dev/null +++ b/src/google/protobuf/json/internal/parser_traits.h @@ -0,0 +1,425 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_JSON_INTERNAL_PARSER_TRAITS_H__ +#define GOOGLE_PROTOBUF_JSON_INTERNAL_PARSER_TRAITS_H__ + +#include +#include +#include +#include +#include +#include + +#include "google/protobuf/type.pb.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/dynamic_message.h" +#include "google/protobuf/message.h" +#include "google/protobuf/wire_format_lite.h" +#include "absl/base/attributes.h" +#include "absl/base/casts.h" +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" +#include "absl/status/status.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" +#include "google/protobuf/io/coded_stream.h" +#include "google/protobuf/io/zero_copy_stream.h" +#include "google/protobuf/io/zero_copy_stream_impl_lite.h" +#include "google/protobuf/json/internal/descriptor_traits.h" +#include "google/protobuf/stubs/status_macros.h" + +// Must be included last. +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace json_internal { +using ::google::protobuf::internal::WireFormatLite; + +// See the comment in json_util2_parser.cc for more information. +// +// The type traits in this file describe how to parse to a protobuf +// representation used by the JSON API, either via proto reflection or by +// emitting wire format to an output stream. + +// Helper alias templates to avoid needing to write `typename` in function +// signatures. +template +using Msg = typename Traits::Msg; + +struct ParseProto2Descriptor : Proto2Descriptor { + // A message value that fields can be written to, but not read from. + class Msg { + public: + explicit Msg(Message* msg) : msg_(msg) {} + + private: + friend ParseProto2Descriptor; + Message* msg_; + // Because `msg` might already have oneofs set, we need to track which were + // set *during* the parse separately. + absl::flat_hash_set parsed_oneofs_indices_; + absl::flat_hash_set parsed_fields_; + }; + + static bool HasParsed(Field f, const Msg& msg, + bool allow_repeated_non_oneof) { + if (f->real_containing_oneof()) { + return msg.parsed_oneofs_indices_.contains( + f->real_containing_oneof()->index()); + } + if (allow_repeated_non_oneof) { + return false; + } + return msg.parsed_fields_.contains(f->number()); + } + + /// Functions for writing fields. /// + + // Marks a field as having been "seen". This will clear the field if it is + // the first occurence thereof. + // + // All setters call this function automatically, but it may also be called + // eagerly to clear a pre-existing value that might not be overwritten, such + // as when parsing a repeated field. + static void RecordAsSeen(Field f, Msg& msg) { + bool inserted = msg.parsed_fields_.insert(f->number()).second; + if (inserted) { + msg.msg_->GetReflection()->ClearField(msg.msg_, f); + } + + if (f->real_containing_oneof() != nullptr) { + msg.parsed_oneofs_indices_.insert(f->real_containing_oneof()->index()); + } + } + + // Adds a new message and calls body on it. + // + // Body should have a signature `absl::Status(const Desc&, Msg&)`. + template + static absl::Status NewMsg(Field f, Msg& msg, F body) { + RecordAsSeen(f, msg); + + Message* new_msg; + if (f->is_repeated()) { + new_msg = msg.msg_->GetReflection()->AddMessage(msg.msg_, f); + } else { + new_msg = msg.msg_->GetReflection()->MutableMessage(msg.msg_, f); + } + Msg wrapper(new_msg); + return body(*f->message_type(), wrapper); + } + + // Adds a new dynamic message with the given type name and calls body on it. + // + // Body should have a signature `absl::Status(const Desc&, Msg&)`. + template + static absl::Status NewDynamic(Field f, const std::string& type_url, Msg& msg, + F body) { + RecordAsSeen(f, msg); + return WithDynamicType( + *f->containing_type(), type_url, [&](const Desc& desc) -> absl::Status { + DynamicMessageFactory factory; + std::unique_ptr dynamic(factory.GetPrototype(&desc)->New()); + Msg wrapper(dynamic.get()); + RETURN_IF_ERROR(body(desc, wrapper)); + + if (f->is_repeated()) { + msg.msg_->GetReflection()->AddString(msg.msg_, f, + dynamic->SerializeAsString()); + } else { + msg.msg_->GetReflection()->SetString(msg.msg_, f, + dynamic->SerializeAsString()); + } + return absl::OkStatus(); + }); + } + + static void SetFloat(Field f, Msg& msg, float x) { + RecordAsSeen(f, msg); + if (f->is_repeated()) { + msg.msg_->GetReflection()->AddFloat(msg.msg_, f, x); + } else { + msg.msg_->GetReflection()->SetFloat(msg.msg_, f, x); + } + } + + static void SetDouble(Field f, Msg& msg, double x) { + if (f->is_repeated()) { + msg.msg_->GetReflection()->AddDouble(msg.msg_, f, x); + } else { + msg.msg_->GetReflection()->SetDouble(msg.msg_, f, x); + } + } + + static void SetInt64(Field f, Msg& msg, int64_t x) { + RecordAsSeen(f, msg); + if (f->is_repeated()) { + msg.msg_->GetReflection()->AddInt64(msg.msg_, f, x); + } else { + msg.msg_->GetReflection()->SetInt64(msg.msg_, f, x); + } + } + + static void SetUInt64(Field f, Msg& msg, uint64_t x) { + RecordAsSeen(f, msg); + if (f->is_repeated()) { + msg.msg_->GetReflection()->AddUInt64(msg.msg_, f, x); + } else { + msg.msg_->GetReflection()->SetUInt64(msg.msg_, f, x); + } + } + + static void SetInt32(Field f, Msg& msg, int32 x) { + RecordAsSeen(f, msg); + if (f->is_repeated()) { + msg.msg_->GetReflection()->AddInt32(msg.msg_, f, x); + } else { + msg.msg_->GetReflection()->SetInt32(msg.msg_, f, x); + } + } + + static void SetUInt32(Field f, Msg& msg, uint32 x) { + RecordAsSeen(f, msg); + if (f->is_repeated()) { + msg.msg_->GetReflection()->AddUInt32(msg.msg_, f, x); + } else { + msg.msg_->GetReflection()->SetUInt32(msg.msg_, f, x); + } + } + + static void SetBool(Field f, Msg& msg, bool x) { + RecordAsSeen(f, msg); + if (f->is_repeated()) { + msg.msg_->GetReflection()->AddBool(msg.msg_, f, x); + } else { + msg.msg_->GetReflection()->SetBool(msg.msg_, f, x); + } + } + + static void SetString(Field f, Msg& msg, absl::string_view x) { + RecordAsSeen(f, msg); + if (f->is_repeated()) { + msg.msg_->GetReflection()->AddString(msg.msg_, f, std::string(x)); + } else { + msg.msg_->GetReflection()->SetString(msg.msg_, f, std::string(x)); + } + } + + static void SetEnum(Field f, Msg& msg, int32_t x) { + RecordAsSeen(f, msg); + if (f->is_repeated()) { + msg.msg_->GetReflection()->AddEnumValue(msg.msg_, f, x); + } else { + msg.msg_->GetReflection()->SetEnumValue(msg.msg_, f, x); + } + } +}; + +// Traits for proto3-ish deserialization. +// +// This includes a rudimentary proto serializer, since message fields are +// written directly instead of being reflectively written to a proto field. +// +// See MessageTraits for API docs. +struct ParseProto3Type : Proto3Type { + class Msg { + public: + explicit Msg(io::ZeroCopyOutputStream* stream) : stream_(stream) {} + + private: + friend ParseProto3Type; + io::CodedOutputStream stream_; + absl::flat_hash_set parsed_oneofs_indices_; + absl::flat_hash_set parsed_fields_; + }; + + static bool HasParsed(Field f, const Msg& msg, + bool allow_repeated_non_oneof) { + if (f->proto().oneof_index() != 0) { + return msg.parsed_oneofs_indices_.contains(f->proto().oneof_index()); + } + if (allow_repeated_non_oneof) { + return false; + } + return msg.parsed_fields_.contains(f->proto().number()); + } + + /// Functions for writing fields. /// + + static void RecordAsSeen(Field f, Msg& msg) { + msg.parsed_fields_.insert(f->proto().number()); + if (f->proto().oneof_index() != 0) { + msg.parsed_oneofs_indices_.insert(f->proto().oneof_index()); + } + } + + template + static absl::Status NewMsg(Field f, Msg& msg, F body) { + return NewDynamic(f, f->proto().type_url(), msg, body); + } + + template + static absl::Status NewDynamic(Field f, const std::string& type_url, Msg& msg, + F body) { + RecordAsSeen(f, msg); + return WithDynamicType( + f->parent(), type_url, [&](const Desc& desc) -> absl::Status { + if (f->proto().kind() == google::protobuf::Field::TYPE_GROUP) { + msg.stream_.WriteTag(f->proto().number() << 3 | + WireFormatLite::WIRETYPE_START_GROUP); + RETURN_IF_ERROR(body(desc, msg)); + msg.stream_.WriteTag(f->proto().number() << 3 | + WireFormatLite::WIRETYPE_END_GROUP); + return absl::OkStatus(); + } + + std::string out; + io::StringOutputStream stream(&out); + Msg new_msg(&stream); + RETURN_IF_ERROR(body(desc, new_msg)); + + new_msg.stream_.Trim(); // Should probably be called "Flush()". + absl::string_view written( + out.data(), static_cast(new_msg.stream_.ByteCount())); + SetString(f, msg, written); + return absl::OkStatus(); + }); + } + + static void SetFloat(Field f, Msg& msg, float x) { + RecordAsSeen(f, msg); + msg.stream_.WriteTag(f->proto().number() << 3 | + WireFormatLite::WIRETYPE_FIXED32); + msg.stream_.WriteLittleEndian32(absl::bit_cast(x)); + } + + static void SetDouble(Field f, Msg& msg, double x) { + RecordAsSeen(f, msg); + msg.stream_.WriteTag(f->proto().number() << 3 | + WireFormatLite::WIRETYPE_FIXED64); + msg.stream_.WriteLittleEndian64(absl::bit_cast(x)); + } + + static void SetInt64(Field f, Msg& msg, int64_t x) { + SetInt(f, msg, x); + } + + static void SetUInt64(Field f, Msg& msg, uint64_t x) { + SetInt(f, msg, x); + } + + static void SetInt32(Field f, Msg& msg, int32_t x) { + SetInt(f, msg, x); + } + + static void SetUInt32(Field f, Msg& msg, uint32_t x) { + SetInt(f, msg, x); + } + + static void SetBool(Field f, Msg& msg, bool x) { + RecordAsSeen(f, msg); + msg.stream_.WriteTag(f->proto().number() << 3); + char b = x ? 0x01 : 0x00; + msg.stream_.WriteRaw(&b, 1); + } + + static void SetString(Field f, Msg& msg, absl::string_view x) { + RecordAsSeen(f, msg); + msg.stream_.WriteTag(f->proto().number() << 3 | + WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + msg.stream_.WriteVarint64(static_cast(x.size())); + msg.stream_.WriteRaw(x.data(), x.size()); + } + + static void SetEnum(Field f, Msg& msg, int32_t x) { + RecordAsSeen(f, msg); + msg.stream_.WriteTag(f->proto().number() << 3); + // Sign extension is deliberate here. + msg.stream_.WriteVarint32(x); + } + + private: + using Kind = google::protobuf::Field::Kind; + // Sets a field of *some* integer type, with the given kinds for the possible + // encodings. This avoids quadruplicating this code in the helpers for the + // four major integer types. + template + static void SetInt(Field f, Msg& msg, Int x) { + RecordAsSeen(f, msg); + switch (f->proto().kind()) { + case zigzag: + // Regardless of the integer type, ZigZag64 will do the right thing, + // because ZigZag is not dependent on the width of the integer: it is + // always `2 * abs(n) + (n < 0)`. + x = static_cast( + internal::WireFormatLite::ZigZagEncode64(static_cast(x))); + ABSL_FALLTHROUGH_INTENDED; + case varint: + msg.stream_.WriteTag(f->proto().number() << 3 | + WireFormatLite::WIRETYPE_VARINT); + if (sizeof(Int) == 4) { + msg.stream_.WriteVarint32(static_cast(x)); + } else { + msg.stream_.WriteVarint64(static_cast(x)); + } + break; + case fixed: { + if (sizeof(Int) == 4) { + msg.stream_.WriteTag(f->proto().number() << 3 | + WireFormatLite::WIRETYPE_FIXED32); + msg.stream_.WriteLittleEndian32(static_cast(x)); + } else { + msg.stream_.WriteTag(f->proto().number() << 3 | + WireFormatLite::WIRETYPE_FIXED64); + msg.stream_.WriteLittleEndian64(static_cast(x)); + } + break; + } + default: { // Unreachable. + } + } + } +}; +} // namespace json_internal +} // namespace protobuf +} // namespace google + +#include "google/protobuf/port_undef.inc" +#endif // GOOGLE_PROTOBUF_JSON_INTERNAL_PARSER_TRAITS_H__ diff --git a/src/google/protobuf/json/internal/test_input_stream.h b/src/google/protobuf/json/internal/test_input_stream.h new file mode 100644 index 0000000000..1a05c9b908 --- /dev/null +++ b/src/google/protobuf/json/internal/test_input_stream.h @@ -0,0 +1,106 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_UTIL_TEST_INPUT_STREAM_H__ +#define GOOGLE_PROTOBUF_UTIL_TEST_INPUT_STREAM_H__ + +#include +#include +#include +#include + +#include "google/protobuf/stubs/logging.h" +#include "google/protobuf/stubs/common.h" +#include "absl/strings/string_view.h" +#include "google/protobuf/io/zero_copy_stream.h" +#include "google/protobuf/stubs/status_macros.h" + +namespace google { +namespace protobuf { +namespace json_internal { +// A ZeroCopyInputStream for writing unit tests. +class TestInputStream final : public io::ZeroCopyInputStream { + public: + TestInputStream(std::initializer_list strings) + : strings_(strings) {} + explicit TestInputStream(std::vector strings) + : strings_(std::move(strings)) {} + ~TestInputStream() override = default; + + size_t Consumed() const { return next_; } + + bool Next(const void** data, int* size) override { + if (next_ == strings_.size()) { + return false; + } + + if (next_ > 0) { + // Destroy the previous string so that ASAN can catch misbehavior + // correctly. + ReconstructAt(&strings_[next_ - 1]); + } + + absl::string_view next = strings_[next_++]; + *data = next.data(); + *size = static_cast(next.size()); + return true; + } + + // TestInputStream currently does not support these members. + void BackUp(int) override { GOOGLE_CHECK(false); } + bool Skip(int) override { + GOOGLE_CHECK(false); + return false; + } + int64_t ByteCount() const override { + GOOGLE_CHECK(false); + return 0; + } + + private: + // Some versions of Clang can't figure out that + // x.std::string::~string() + // is valid syntax, so we indirect through a type param, instead. + // + // Of course, our luck has it that std::destroy_at is a C++17 feature. :) + template + static void ReconstructAt(T* p) { + p->~T(); + new (p) T; + } + + std::vector strings_; + size_t next_ = 0; +}; +} // namespace json_internal +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_UTIL_TEST_INPUT_STREAM_H__ diff --git a/src/google/protobuf/json/internal/unparser.cc b/src/google/protobuf/json/internal/unparser.cc new file mode 100644 index 0000000000..6b83019963 --- /dev/null +++ b/src/google/protobuf/json/internal/unparser.cc @@ -0,0 +1,880 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/json/internal/unparser.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "google/protobuf/stubs/logging.h" +#include "google/protobuf/stubs/common.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/dynamic_message.h" +#include "google/protobuf/message.h" +#include "absl/status/status.h" +#include "absl/strings/ascii.h" +#include "absl/strings/escaping.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "google/protobuf/io/coded_stream.h" +#include "google/protobuf/io/zero_copy_stream.h" +#include "google/protobuf/json/internal/descriptor_traits.h" +#include "google/protobuf/json/internal/unparser_traits.h" +#include "google/protobuf/json/internal/writer.h" +#include "google/protobuf/stubs/status_macros.h" + +// Must be included last. +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace json_internal { +namespace { +template +bool IsEmpty(const Msg& msg, const Desc& desc) { + size_t count = Traits::FieldCount(desc); + for (size_t i = 0; i < count; ++i) { + if (Traits::GetSize(Traits::FieldByIndex(desc, i), msg) > 0) { + return false; + } + } + return true; +} + +enum class IntegerEnumStyle { + kQuoted, + kUnquoted, +}; + +template +void WriteEnum(JsonWriter& writer, Field field, int32_t value, + IntegerEnumStyle int_style = IntegerEnumStyle::kUnquoted) { + if (ClassifyMessage(Traits::FieldTypeName(field)) == MessageType::kNull) { + writer.Write("null"); + return; + } + + if (!writer.options().always_print_enums_as_ints) { + auto name = Traits::EnumNameByNumber(field, value); + if (name.ok()) { + writer.Write("\"", *name, "\""); + return; + } + } + + if (int_style == IntegerEnumStyle::kQuoted) { + writer.Write("\"", value, "\""); + } else { + writer.Write(value); + } +} + +// Mutually recursive with functions that follow. +template +absl::Status WriteMessage(JsonWriter& writer, const Msg& msg, + const Desc& desc, bool is_top_level = false); + +// This is templatized so that defaults, singular, and repeated fields can both +// use the same enormous switch-case. +template +absl::Status WriteSingular(JsonWriter& writer, Field field, + Args&&... args) { + // When the pack `args` is empty, the caller has requested printing the + // default value. + bool is_default = sizeof...(Args) == 0; + switch (Traits::FieldType(field)) { + case FieldDescriptor::TYPE_FLOAT: { + auto x = Traits::GetFloat(field, std::forward(args)...); + RETURN_IF_ERROR(x.status()); + if (writer.options().allow_legacy_syntax && is_default && + !std::isfinite(*x)) { + *x = 0; + } + writer.Write(*x); + break; + } + case FieldDescriptor::TYPE_DOUBLE: { + auto x = Traits::GetDouble(field, std::forward(args)...); + RETURN_IF_ERROR(x.status()); + if (writer.options().allow_legacy_syntax && is_default && + !std::isfinite(*x)) { + *x = 0; + } + writer.Write(*x); + break; + } + case FieldDescriptor::TYPE_SFIXED64: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_INT64: { + auto x = Traits::GetInt64(field, std::forward(args)...); + RETURN_IF_ERROR(x.status()); + writer.Write(MakeQuoted(*x)); + break; + } + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_UINT64: { + auto x = Traits::GetUInt64(field, std::forward(args)...); + RETURN_IF_ERROR(x.status()); + writer.Write(MakeQuoted(*x)); + break; + } + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_INT32: { + auto x = Traits::GetInt32(field, std::forward(args)...); + RETURN_IF_ERROR(x.status()); + writer.Write(*x); + break; + } + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_UINT32: { + auto x = Traits::GetUInt32(field, std::forward(args)...); + RETURN_IF_ERROR(x.status()); + writer.Write(*x); + break; + } + case FieldDescriptor::TYPE_BOOL: { + auto x = Traits::GetBool(field, std::forward(args)...); + RETURN_IF_ERROR(x.status()); + writer.Write(*x ? "true" : "false"); + break; + } + case FieldDescriptor::TYPE_STRING: { + auto x = Traits::GetString(field, writer.ScratchBuf(), + std::forward(args)...); + RETURN_IF_ERROR(x.status()); + writer.Write(MakeQuoted(*x)); + break; + } + case FieldDescriptor::TYPE_BYTES: { + auto x = Traits::GetString(field, writer.ScratchBuf(), + std::forward(args)...); + RETURN_IF_ERROR(x.status()); + if (writer.options().allow_legacy_syntax && is_default) { + // Although difficult to verify, it appears that the original ESF parser + // fails to unescape the contents of a + // google.protobuf.Field.default_value, which may potentially be + // escaped if it is for a `bytes` field (note that default_value is a + // `string` regardless of what type the field is). + // + // However, our parser's type.proto guts actually know to do this + // correctly, so this bug must be manually re-introduced. + writer.WriteBase64(absl::CEscape(*x)); + } else { + writer.WriteBase64(*x); + } + break; + } + case FieldDescriptor::TYPE_ENUM: { + auto x = Traits::GetEnumValue(field, std::forward(args)...); + RETURN_IF_ERROR(x.status()); + WriteEnum(writer, field, *x); + break; + } + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: { + auto x = Traits::GetMessage(field, std::forward(args)...); + RETURN_IF_ERROR(x.status()); + return WriteMessage(writer, **x, Traits::GetDesc(**x)); + } + default: + return absl::InvalidArgumentError( + absl::StrCat("unsupported field type: ", Traits::FieldType(field))); + } + + return absl::OkStatus(); +} + +template +absl::Status WriteRepeated(JsonWriter& writer, const Msg& msg, + Field field) { + writer.Write("["); + writer.Push(); + + size_t count = Traits::GetSize(field, msg); + bool first = true; + for (size_t i = 0; i < count; ++i) { + if (ClassifyMessage(Traits::FieldTypeName(field)) == MessageType::kValue) { + bool empty = false; + RETURN_IF_ERROR(Traits::WithFieldType( + field, [&](const Desc& desc) -> absl::Status { + auto inner = Traits::GetMessage(field, msg, i); + RETURN_IF_ERROR(inner.status()); + empty = IsEmpty(**inner, desc); + return absl::OkStatus(); + })); + + // Empty google.protobuf.Values are silently discarded. + if (empty) { + continue; + } + } + writer.WriteComma(first); + writer.NewLine(); + RETURN_IF_ERROR(WriteSingular(writer, field, msg, i)); + } + + writer.Pop(); + if (!first) { + writer.NewLine(); + } + writer.Write("]"); + return absl::OkStatus(); +} + +template +absl::Status WriteMapKey(JsonWriter& writer, const Msg& entry, + Field field) { + switch (Traits::FieldType(field)) { + case FieldDescriptor::TYPE_SFIXED64: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_INT64: { + auto x = Traits::GetInt64(field, entry); + RETURN_IF_ERROR(x.status()); + writer.Write(MakeQuoted(*x)); + break; + } + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_UINT64: { + auto x = Traits::GetUInt64(field, entry); + RETURN_IF_ERROR(x.status()); + writer.Write(MakeQuoted(*x)); + break; + } + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_INT32: { + auto x = Traits::GetInt32(field, entry); + RETURN_IF_ERROR(x.status()); + writer.Write(MakeQuoted(*x)); + break; + } + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_UINT32: { + auto x = Traits::GetUInt32(field, entry); + RETURN_IF_ERROR(x.status()); + writer.Write(MakeQuoted(*x)); + break; + } + case FieldDescriptor::TYPE_BOOL: { + auto x = Traits::GetBool(field, entry); + RETURN_IF_ERROR(x.status()); + writer.Write(MakeQuoted(*x ? "true" : "false")); + break; + } + case FieldDescriptor::TYPE_STRING: { + auto x = Traits::GetString(field, writer.ScratchBuf(), entry); + RETURN_IF_ERROR(x.status()); + writer.Write(MakeQuoted(*x)); + break; + } + case FieldDescriptor::TYPE_ENUM: { + auto x = Traits::GetEnumValue(field, entry); + RETURN_IF_ERROR(x.status()); + WriteEnum(writer, field, *x, IntegerEnumStyle::kQuoted); + break; + } + default: + return absl::InvalidArgumentError( + absl::StrCat("unsupported map key type: ", Traits::FieldType(field))); + } + return absl::OkStatus(); +} + +template +absl::StatusOr IsEmptyValue(const Msg& msg, Field field) { + if (ClassifyMessage(Traits::FieldTypeName(field)) != MessageType::kValue) { + return false; + } + bool empty = false; + RETURN_IF_ERROR(Traits::WithFieldType( + field, [&](const Desc& desc) -> absl::Status { + auto inner = Traits::GetMessage(field, msg); + RETURN_IF_ERROR(inner.status()); + empty = IsEmpty(**inner, desc); + return absl::OkStatus(); + })); + return empty; +} + +template +absl::Status WriteMap(JsonWriter& writer, const Msg& msg, + Field field) { + writer.Write("{"); + writer.Push(); + + size_t count = Traits::GetSize(field, msg); + bool first = true; + for (size_t i = 0; i < count; ++i) { + absl::StatusOr*> entry = + Traits::GetMessage(field, msg, i); + RETURN_IF_ERROR(entry.status()); + const Desc& type = Traits::GetDesc(**entry); + + auto is_empty = IsEmptyValue(**entry, Traits::ValueField(type)); + RETURN_IF_ERROR(is_empty.status()); + if (*is_empty) { + // Empty google.protobuf.Values are silently discarded. + continue; + } + + writer.WriteComma(first); + writer.NewLine(); + RETURN_IF_ERROR( + WriteMapKey(writer, **entry, Traits::KeyField(type))); + writer.Write(":"); + writer.Whitespace(" "); + RETURN_IF_ERROR( + WriteSingular(writer, Traits::ValueField(type), **entry)); + } + + writer.Pop(); + if (!first) { + writer.NewLine(); + } + writer.Write("}"); + return absl::OkStatus(); +} + +template +absl::Status WriteField(JsonWriter& writer, const Msg& msg, + Field field, bool& first) { + if (!Traits::IsRepeated(field)) { // Repeated case is handled in + // WriteRepeated. + auto is_empty = IsEmptyValue(msg, field); + RETURN_IF_ERROR(is_empty.status()); + if (*is_empty) { + // Empty google.protobuf.Values are silently discarded. + return absl::OkStatus(); + } + } + + writer.WriteComma(first); + writer.NewLine(); + + if (Traits::IsExtension(field)) { + writer.Write(MakeQuoted("[", Traits::FieldFullName(field), "]"), ":"); + } else if (writer.options().preserve_proto_field_names) { + writer.Write(MakeQuoted(Traits::FieldName(field)), ":"); + } else { + // The generator for type.proto and the internals of descriptor.cc disagree + // on what the json name of a PascalCase field is supposed to be; type.proto + // seems to (incorrectly?) capitalize the first letter, which is the + // behavior ESF defaults to. To fix this, if the original field name starts + // with an uppercase letter, and the Json name does not, we uppercase it. + absl::string_view original_name = Traits::FieldName(field); + absl::string_view json_name = Traits::FieldJsonName(field); + if (writer.options().allow_legacy_syntax && + absl::ascii_isupper(original_name[0]) && + !absl::ascii_isupper(json_name[0])) { + writer.Write(MakeQuoted(absl::ascii_toupper(original_name[0]), + original_name.substr(1)), + ":"); + } else { + writer.Write(MakeQuoted(json_name), ":"); + } + } + writer.Whitespace(" "); + + if (Traits::IsMap(field)) { + return WriteMap(writer, msg, field); + } else if (Traits::IsRepeated(field)) { + return WriteRepeated(writer, msg, field); + } else if (Traits::GetSize(field, msg) == 0) { + // We can only get here if always_print_primitive_fields is true. + GOOGLE_DCHECK(writer.options().always_print_primitive_fields); + + if (Traits::FieldType(field) == FieldDescriptor::TYPE_GROUP) { + // We do not yet have full group support, but this is required so that we + // pass the same tests as the ESF parser. + writer.Write("null"); + return absl::OkStatus(); + } + return WriteSingular(writer, field); + } + + return WriteSingular(writer, field, msg); +} + +template +absl::Status WriteFields(JsonWriter& writer, const Msg& msg, + const Desc& desc, bool& first) { + std::vector> fields; + size_t total = Traits::FieldCount(desc); + fields.reserve(total); + for (size_t i = 0; i < total; ++i) { + Field field = Traits::FieldByIndex(desc, i); + + bool has = Traits::GetSize(field, msg) > 0; + if (writer.options().always_print_primitive_fields) { + bool is_singular_message = + !Traits::IsRepeated(field) && + Traits::FieldType(field) == FieldDescriptor::TYPE_MESSAGE; + has |= !is_singular_message && !Traits::IsOneof(field); + } + + if (has) { + fields.push_back(field); + } + } + + // Add extensions *before* sorting. + Traits::FindAndAppendExtensions(msg, fields); + + // Fields are guaranteed to be serialized in field number order. + absl::c_sort(fields, [](const auto& a, const auto& b) { + return Traits::FieldNumber(a) < Traits::FieldNumber(b); + }); + + for (auto field : fields) { + RETURN_IF_ERROR(WriteField(writer, msg, field, first)); + } + + return absl::OkStatus(); +} + +template +absl::Status WriteStructValue(JsonWriter& writer, const Msg& msg, + const Desc& desc); +template +absl::Status WriteListValue(JsonWriter& writer, const Msg& msg, + const Desc& desc); + +template +absl::Status WriteValue(JsonWriter& writer, const Msg& msg, + const Desc& desc, bool is_top_level) { + // NOTE: The field numbers 1 through 6 are the numbers of the oneof fields in + // google.protobuf.Value. Conformance tests verify the correctness of these + // numbers. + if (Traits::GetSize(Traits::MustHaveField(desc, 1), msg) > 0) { + writer.Write("null"); + return absl::OkStatus(); + } + + auto number_field = Traits::MustHaveField(desc, 2); + if (Traits::GetSize(number_field, msg) > 0) { + auto x = Traits::GetDouble(number_field, msg); + RETURN_IF_ERROR(x.status()); + writer.Write(*x); + return absl::OkStatus(); + } + + auto string_field = Traits::MustHaveField(desc, 3); + if (Traits::GetSize(string_field, msg) > 0) { + auto x = Traits::GetString(string_field, writer.ScratchBuf(), msg); + RETURN_IF_ERROR(x.status()); + writer.Write(MakeQuoted(*x)); + return absl::OkStatus(); + } + + auto bool_field = Traits::MustHaveField(desc, 4); + if (Traits::GetSize(bool_field, msg) > 0) { + auto x = Traits::GetBool(bool_field, msg); + RETURN_IF_ERROR(x.status()); + writer.Write(*x ? "true" : "false"); + return absl::OkStatus(); + } + + auto struct_field = Traits::MustHaveField(desc, 5); + if (Traits::GetSize(struct_field, msg) > 0) { + auto x = Traits::GetMessage(struct_field, msg); + RETURN_IF_ERROR(x.status()); + return Traits::WithFieldType(struct_field, [&](const Desc& type) { + return WriteStructValue(writer, **x, type); + }); + } + + auto list_field = Traits::MustHaveField(desc, 6); + if (Traits::GetSize(list_field, msg) > 0) { + auto x = Traits::GetMessage(list_field, msg); + RETURN_IF_ERROR(x.status()); + return Traits::WithFieldType(list_field, [&](const Desc& type) { + return WriteListValue(writer, **x, type); + }); + } + + GOOGLE_CHECK(is_top_level) << "empty, non-top-level Value must be handled one layer " + "up, since it prints an empty string; reaching this " + "statement is always a bug"; + return absl::OkStatus(); +} + +template +absl::Status WriteStructValue(JsonWriter& writer, const Msg& msg, + const Desc& desc) { + return WriteMap(writer, msg, Traits::MustHaveField(desc, 1)); +} + +template +absl::Status WriteListValue(JsonWriter& writer, const Msg& msg, + const Desc& desc) { + return WriteRepeated(writer, msg, Traits::MustHaveField(desc, 1)); +} + +template +absl::Status WriteTimestamp(JsonWriter& writer, const Msg& msg, + const Desc& desc) { + auto secs_field = Traits::MustHaveField(desc, 1); + auto secs = Traits::GetSize(secs_field, msg) > 0 + ? Traits::GetInt64(secs_field, msg) + : 0; + RETURN_IF_ERROR(secs.status()); + + if (*secs < -62135596800) { + return absl::InvalidArgumentError( + "minimum acceptable time value is 0001-01-01T00:00:00Z"); + } else if (*secs > 253402300799) { + return absl::InvalidArgumentError( + "maximum acceptable time value is 9999-12-31T23:59:59Z"); + } + + // Ensure seconds is positive. + *secs += 62135596800; + + auto nanos_field = Traits::MustHaveField(desc, 2); + auto nanos = Traits::GetSize(nanos_field, msg) > 0 + ? Traits::GetInt32(nanos_field, msg) + : 0; + RETURN_IF_ERROR(nanos.status()); + + // Julian Day -> Y/M/D, Algorithm from: + // Fliegel, H. F., and Van Flandern, T. C., "A Machine Algorithm for + // Processing Calendar Dates," Communications of the Association of + // Computing Machines, vol. 11 (1968), p. 657. + int32_t L, N, I, J, K; + L = static_cast(*secs / 86400) - 719162 + 68569 + 2440588; + N = 4 * L / 146097; + L = L - (146097 * N + 3) / 4; + I = 4000 * (L + 1) / 1461001; + L = L - 1461 * I / 4 + 31; + J = 80 * L / 2447; + K = L - 2447 * J / 80; + L = J / 11; + J = J + 2 - 12 * L; + I = 100 * (N - 49) + I + L; + + int32_t sec = *secs % 60; + int32_t min = (*secs / 60) % 60; + int32_t hour = (*secs / 3600) % 24; + + if (*nanos == 0) { + writer.Write(absl::StrFormat(R"("%04d-%02d-%02dT%02d:%02d:%02dZ")", I, J, K, + hour, min, sec)); + return absl::OkStatus(); + } + + size_t digits = 9; + uint32_t frac_seconds = std::abs(*nanos); + while (frac_seconds % 1000 == 0) { + frac_seconds /= 1000; + digits -= 3; + } + + writer.Write(absl::StrFormat(R"("%04d-%02d-%02dT%02d:%02d:%02d.%.*dZ")", I, J, + K, hour, min, sec, digits, frac_seconds)); + return absl::OkStatus(); +} + +template +absl::Status WriteDuration(JsonWriter& writer, const Msg& msg, + const Desc& desc) { + constexpr int64_t kMaxSeconds = int64_t{3652500} * 86400; + constexpr int64_t kMaxNanos = 999999999; + + auto secs_field = Traits::MustHaveField(desc, 1); + auto secs = Traits::GetSize(secs_field, msg) > 0 + ? Traits::GetInt64(secs_field, msg) + : 0; + RETURN_IF_ERROR(secs.status()); + + if (*secs > kMaxSeconds || *secs < -kMaxSeconds) { + return absl::InvalidArgumentError("duration out of range"); + } + + auto nanos_field = Traits::MustHaveField(desc, 2); + auto nanos = Traits::GetSize(nanos_field, msg) > 0 + ? Traits::GetInt32(nanos_field, msg) + : 0; + RETURN_IF_ERROR(nanos.status()); + + if (*nanos > kMaxNanos || *nanos < -kMaxNanos) { + return absl::InvalidArgumentError("duration out of range"); + } + if ((*secs != 0) && (*nanos != 0) && ((*secs < 0) != (*nanos < 0))) { + return absl::InvalidArgumentError("nanos and seconds signs do not match"); + } + + if (*nanos == 0) { + writer.Write(absl::StrFormat(R"("%ds")", *secs)); + return absl::OkStatus(); + } + + size_t digits = 9; + uint32_t frac_seconds = std::abs(*nanos); + while (frac_seconds % 1000 == 0) { + frac_seconds /= 1000; + digits -= 3; + } + + absl::string_view sign = ((*secs < 0) || (*nanos < 0)) ? "-" : ""; + writer.Write(absl::StrFormat(R"("%s%d.%.*ds")", sign, std::abs(*secs), digits, + frac_seconds)); + return absl::OkStatus(); +} + +template +absl::Status WriteFieldMask(JsonWriter& writer, const Msg& msg, + const Desc& desc) { + // google.protobuf.FieldMask has a single field with number 1. + auto paths_field = Traits::MustHaveField(desc, 1); + size_t paths = Traits::GetSize(paths_field, msg); + writer.Write('"'); + + bool first = true; + for (size_t i = 0; i < paths; ++i) { + writer.WriteComma(first); + auto path = Traits::GetString(paths_field, writer.ScratchBuf(), msg, i); + RETURN_IF_ERROR(path.status()); + bool saw_under = false; + for (char c : *path) { + if (absl::ascii_islower(c) && saw_under) { + writer.Write(absl::ascii_toupper(c)); + } else if (absl::ascii_isdigit(c) || absl::ascii_islower(c) || c == '.') { + writer.Write(c); + } else if (c == '_' && + (!saw_under || writer.options().allow_legacy_syntax)) { + saw_under = true; + continue; + } else if (!writer.options().allow_legacy_syntax) { + return absl::InvalidArgumentError("unexpected character in FieldMask"); + } else { + if (saw_under) { + writer.Write('_'); + } + writer.Write(c); + } + saw_under = false; + } + } + writer.Write('"'); + + return absl::OkStatus(); +} + +template +absl::Status WriteAny(JsonWriter& writer, const Msg& msg, + const Desc& desc) { + auto type_url_field = Traits::MustHaveField(desc, 1); + auto value_field = Traits::MustHaveField(desc, 2); + + bool has_type_url = Traits::GetSize(type_url_field, msg) > 0; + bool has_value = Traits::GetSize(value_field, msg) > 0; + if (!has_type_url && !has_value) { + writer.Write("{}"); + return absl::OkStatus(); + } else if (!has_type_url) { + return absl::InvalidArgumentError("broken Any: missing type URL"); + } else if (!has_value && !writer.options().allow_legacy_syntax) { + return absl::InvalidArgumentError("broken Any: missing value"); + } + + writer.Write("{"); + writer.Push(); + + auto type_url = Traits::GetString(type_url_field, writer.ScratchBuf(), msg); + RETURN_IF_ERROR(type_url.status()); + writer.NewLine(); + writer.Write("\"@type\":"); + writer.Whitespace(" "); + writer.Write(MakeQuoted(*type_url)); + + return Traits::WithDynamicType( + desc, std::string(*type_url), + [&](const Desc& any_desc) -> absl::Status { + absl::string_view any_bytes; + if (has_value) { + absl::StatusOr bytes = + Traits::GetString(value_field, writer.ScratchBuf(), msg); + RETURN_IF_ERROR(bytes.status()); + any_bytes = *bytes; + } + + return Traits::WithDecodedMessage( + any_desc, any_bytes, + [&](const Msg& unerased) -> absl::Status { + bool first = false; + if (ClassifyMessage(Traits::TypeName(any_desc)) != + MessageType::kNotWellKnown) { + writer.WriteComma(first); + writer.NewLine(); + writer.Write("\"value\":"); + writer.Whitespace(" "); + RETURN_IF_ERROR( + WriteMessage(writer, unerased, any_desc)); + } else { + RETURN_IF_ERROR( + WriteFields(writer, unerased, any_desc, first)); + } + writer.Pop(); + if (!first) { + writer.NewLine(); + } + writer.Write("}"); + return absl::OkStatus(); + }); + }); +} + +template +absl::Status WriteMessage(JsonWriter& writer, const Msg& msg, + const Desc& desc, bool is_top_level) { + switch (ClassifyMessage(Traits::TypeName(desc))) { + case MessageType::kAny: + return WriteAny(writer, msg, desc); + case MessageType::kWrapper: { + auto field = Traits::MustHaveField(desc, 1); + if (Traits::GetSize(field, msg) == 0) { + return WriteSingular(writer, field); + } + return WriteSingular(writer, field, msg); + } + case MessageType::kValue: + return WriteValue(writer, msg, desc, is_top_level); + case MessageType::kStruct: + return WriteStructValue(writer, msg, desc); + case MessageType::kList: + return WriteListValue(writer, msg, desc); + case MessageType::kTimestamp: + return WriteTimestamp(writer, msg, desc); + case MessageType::kDuration: + return WriteDuration(writer, msg, desc); + case MessageType::kFieldMask: + return WriteFieldMask(writer, msg, desc); + default: { + writer.Write("{"); + writer.Push(); + bool first = true; + RETURN_IF_ERROR(WriteFields(writer, msg, desc, first)); + writer.Pop(); + if (!first) { + writer.NewLine(); + } + writer.Write("}"); + return absl::OkStatus(); + } + } +} +} // namespace + +absl::Status MessageToJsonString(const Message& message, std::string* output, + json_internal::WriterOptions options) { + PROTOBUF_DLOG(INFO) << "json2/input: " << message.DebugString(); + io::StringOutputStream out(output); + JsonWriter writer(&out, options); + absl::Status s = WriteMessage( + writer, message, *message.GetDescriptor(), /*is_top_level=*/true); + PROTOBUF_DLOG(INFO) << "json2/status: " << s; + RETURN_IF_ERROR(s); + + writer.NewLine(); + PROTOBUF_DLOG(INFO) << "json2/output: " << absl::CHexEscape(*output); + return absl::OkStatus(); +} + +absl::Status BinaryToJsonStream(google::protobuf::util::TypeResolver* resolver, + const std::string& type_url, + io::ZeroCopyInputStream* binary_input, + io::ZeroCopyOutputStream* json_output, + json_internal::WriterOptions options) { + // NOTE: Most of the contortions in this function are to allow for capture of + // input and output of the parser in GOOGLE_DLOG mode. Destruction order is very + // critical in this function, because io::ZeroCopy*Stream types usually only + // flush on destruction. + + // For GOOGLE_DLOG, we would like to print out the input and output, which requires + // buffering both instead of doing "zero copy". This block, and the one at + // the end of the function, set up and tear down interception of the input + // and output streams. + std::string copy; + std::string out; + absl::optional tee_input; + absl::optional tee_output; + if (PROTOBUF_DEBUG) { + const void* data; + int len; + while (binary_input->Next(&data, &len)) { + copy.resize(copy.size() + len); + std::memcpy(©[copy.size() - len], data, len); + } + tee_input.emplace(copy.data(), copy.size()); + tee_output.emplace(&out); + } + + PROTOBUF_DLOG(INFO) << "json2/input: " << absl::BytesToHexString(copy); + + ResolverPool pool(resolver); + auto desc = pool.FindMessage(type_url); + RETURN_IF_ERROR(desc.status()); + + io::CodedInputStream stream(tee_input.has_value() ? &*tee_input + : binary_input); + auto msg = UntypedMessage::ParseFromStream(*desc, stream); + RETURN_IF_ERROR(msg.status()); + + JsonWriter writer(tee_output.has_value() ? &*tee_output : json_output, + options); + absl::Status s = WriteMessage( + writer, *msg, UnparseProto3Type::GetDesc(*msg), + /*is_top_level=*/true); + PROTOBUF_DLOG(INFO) << "json2/status: " << s; + RETURN_IF_ERROR(s); + + if (PROTOBUF_DEBUG) { + tee_output.reset(); // Flush the output stream. + io::zc_sink_internal::ZeroCopyStreamByteSink(json_output) + .Append(out.data(), out.size()); + } + + PROTOBUF_DLOG(INFO) << "json2/output: " << absl::CHexEscape(out); + + writer.NewLine(); + return absl::OkStatus(); +} +} // namespace json_internal +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/util/internal/location_tracker.h b/src/google/protobuf/json/internal/unparser.h similarity index 61% rename from src/google/protobuf/util/internal/location_tracker.h rename to src/google/protobuf/json/internal/unparser.h index 4cec03ec82..a9a935d6a2 100644 --- a/src/google/protobuf/util/internal/location_tracker.h +++ b/src/google/protobuf/json/internal/unparser.h @@ -28,44 +28,32 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_LOCATION_TRACKER_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_LOCATION_TRACKER_H__ +#ifndef GOOGLE_PROTOBUF_JSON_INTERNAL_UNPARSER_H__ +#define GOOGLE_PROTOBUF_JSON_INTERNAL_UNPARSER_H__ #include -#include "google/protobuf/port.h" - -// Must be included last. -#include "google/protobuf/port_def.inc" +#include "google/protobuf/message.h" +#include "absl/strings/string_view.h" +#include "google/protobuf/json/internal/writer.h" +#include "google/protobuf/util/type_resolver.h" namespace google { namespace protobuf { -namespace util { -namespace converter { - -// LocationTrackerInterface is an interface for classes that track -// the location information for the purpose of error reporting. -class PROTOBUF_EXPORT LocationTrackerInterface { - public: - LocationTrackerInterface(const LocationTrackerInterface&) = delete; - LocationTrackerInterface& operator=(const LocationTrackerInterface&) = delete; - virtual ~LocationTrackerInterface() {} - - // Returns the object location as human readable string. - virtual std::string ToString() const = 0; - - protected: - LocationTrackerInterface() {} - - private: - // Please do not add any data members to this class. -}; - -} // namespace converter -} // namespace util +namespace json_internal { +// Internal version of google::protobuf::util::MessageToJsonString; see json_util.h for +// details. +absl::Status MessageToJsonString(const Message& message, std::string* output, + json_internal::WriterOptions options); +// Internal version of google::protobuf::util::BinaryToJsonStream; see json_util.h for +// details. +absl::Status BinaryToJsonStream(google::protobuf::util::TypeResolver* resolver, + const std::string& type_url, + io::ZeroCopyInputStream* binary_input, + io::ZeroCopyOutputStream* json_output, + json_internal::WriterOptions options); +} // namespace json_internal } // namespace protobuf } // namespace google -#include "google/protobuf/port_undef.inc" - -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_LOCATION_TRACKER_H__ +#endif // GOOGLE_PROTOBUF_JSON_INTERNAL_UNPARSER_H__ diff --git a/src/google/protobuf/json/internal/unparser_traits.h b/src/google/protobuf/json/internal/unparser_traits.h new file mode 100644 index 0000000000..9e1f3efc9b --- /dev/null +++ b/src/google/protobuf/json/internal/unparser_traits.h @@ -0,0 +1,443 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_JSON_INTERNAL_UNPARSER_TRAITS_H__ +#define GOOGLE_PROTOBUF_JSON_INTERNAL_UNPARSER_TRAITS_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "google/protobuf/type.pb.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/dynamic_message.h" +#include "google/protobuf/message.h" +#include "google/protobuf/wire_format.h" +#include "google/protobuf/wire_format_lite.h" +#include "absl/container/flat_hash_map.h" +#include "absl/status/status.h" +#include "absl/strings/escaping.h" +#include "absl/strings/numbers.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "absl/types/variant.h" +#include "google/protobuf/io/coded_stream.h" +#include "google/protobuf/json/internal/descriptor_traits.h" +#include "google/protobuf/stubs/status_macros.h" + +// Must be included last. +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace json_internal { +// The type traits in this file provide describe how to read from protobuf +// representation used by the JSON API, either via proto reflection or via +// something ad-hoc for type.proto. + +// Helper alias templates to avoid needing to write `typename` in function +// signatures. +template +using Msg = typename Traits::Msg; + +// Traits for proto2-ish deserialization. +struct UnparseProto2Descriptor : Proto2Descriptor { + // A message value that fields can be read from. + using Msg = Message; + + static const Desc& GetDesc(const Msg& msg) { return *msg.GetDescriptor(); } + + // Appends extension fields to `fields`. + static void FindAndAppendExtensions(const Msg& msg, + std::vector& fields) { + // Note that it is *not* correct to use ListFields for getting a list of + // fields to write, because the way that JSON decides to print non-extension + // fields is slightly subtle. That logic is handled elsewhere; we're only + // here to get extensions. + std::vector all_fields; + msg.GetReflection()->ListFields(msg, &all_fields); + + for (Field field : all_fields) { + if (field->is_extension()) { + fields.push_back(field); + } + } + } + + static size_t GetSize(Field f, const Msg& msg) { + if (f->is_repeated()) { + return msg.GetReflection()->FieldSize(msg, f); + } else { + return msg.GetReflection()->HasField(msg, f) ? 1 : 0; + } + } + + static absl::StatusOr GetFloat(Field f) { + return f->default_value_float(); + } + + static absl::StatusOr GetDouble(Field f) { + return f->default_value_double(); + } + + static absl::StatusOr GetInt32(Field f) { + return f->default_value_int32(); + } + + static absl::StatusOr GetUInt32(Field f) { + return f->default_value_uint32(); + } + + static absl::StatusOr GetInt64(Field f) { + return f->default_value_int64(); + } + + static absl::StatusOr GetUInt64(Field f) { + return f->default_value_uint64(); + } + + static absl::StatusOr GetBool(Field f) { + return f->default_value_bool(); + } + + static absl::StatusOr GetEnumValue(Field f) { + return f->default_value_enum()->number(); + } + + static absl::StatusOr GetString(Field f, + std::string& scratch) { + return f->default_value_string(); + } + + static absl::StatusOr GetMessage(Field f) { + return absl::InternalError("message fields cannot have defaults"); + } + + static absl::StatusOr GetFloat(Field f, const Msg& msg) { + return msg.GetReflection()->GetFloat(msg, f); + } + + static absl::StatusOr GetDouble(Field f, const Msg& msg) { + return msg.GetReflection()->GetDouble(msg, f); + } + + static absl::StatusOr GetInt32(Field f, const Msg& msg) { + return msg.GetReflection()->GetInt32(msg, f); + } + + static absl::StatusOr GetUInt32(Field f, const Msg& msg) { + return msg.GetReflection()->GetUInt32(msg, f); + } + + static absl::StatusOr GetInt64(Field f, const Msg& msg) { + return msg.GetReflection()->GetInt64(msg, f); + } + + static absl::StatusOr GetUInt64(Field f, const Msg& msg) { + return msg.GetReflection()->GetUInt64(msg, f); + } + + static absl::StatusOr GetBool(Field f, const Msg& msg) { + return msg.GetReflection()->GetBool(msg, f); + } + + static absl::StatusOr GetEnumValue(Field f, const Msg& msg) { + return msg.GetReflection()->GetEnumValue(msg, f); + } + + static absl::StatusOr GetString(Field f, + std::string& scratch, + const Msg& msg) { + return msg.GetReflection()->GetStringReference(msg, f, &scratch); + } + + static absl::StatusOr GetMessage(Field f, const Msg& msg) { + return &msg.GetReflection()->GetMessage(msg, f); + } + + static absl::StatusOr GetFloat(Field f, const Msg& msg, size_t idx) { + return msg.GetReflection()->GetRepeatedFloat(msg, f, idx); + } + + static absl::StatusOr GetDouble(Field f, const Msg& msg, size_t idx) { + return msg.GetReflection()->GetRepeatedDouble(msg, f, idx); + } + + static absl::StatusOr GetInt32(Field f, const Msg& msg, size_t idx) { + return msg.GetReflection()->GetRepeatedInt32(msg, f, idx); + } + + static absl::StatusOr GetUInt32(Field f, const Msg& msg, + size_t idx) { + return msg.GetReflection()->GetRepeatedUInt32(msg, f, idx); + } + + static absl::StatusOr GetInt64(Field f, const Msg& msg, size_t idx) { + return msg.GetReflection()->GetRepeatedInt64(msg, f, idx); + } + + static absl::StatusOr GetUInt64(Field f, const Msg& msg, + size_t idx) { + return msg.GetReflection()->GetRepeatedUInt64(msg, f, idx); + } + + static absl::StatusOr GetBool(Field f, const Msg& msg, size_t idx) { + return msg.GetReflection()->GetRepeatedBool(msg, f, idx); + } + + static absl::StatusOr GetEnumValue(Field f, const Msg& msg, + size_t idx) { + return msg.GetReflection()->GetRepeatedEnumValue(msg, f, idx); + } + + static absl::StatusOr GetString(Field f, + std::string& scratch, + const Msg& msg, + size_t idx) { + return msg.GetReflection()->GetRepeatedStringReference(msg, f, idx, + &scratch); + } + + static absl::StatusOr GetMessage(Field f, const Msg& msg, + size_t idx) { + return &msg.GetReflection()->GetRepeatedMessage(msg, f, idx); + } + + template + static absl::Status WithDecodedMessage(const Desc& desc, + absl::string_view data, F body) { + DynamicMessageFactory factory; + std::unique_ptr unerased(factory.GetPrototype(&desc)->New()); + unerased->ParseFromString(data); + + // Explicitly create a const reference, so that we do not accidentally pass + // a mutable reference to `body`. + const Msg& ref = *unerased; + return body(ref); + } +}; + +struct UnparseProto3Type : Proto3Type { + using Msg = UntypedMessage; + + static const Desc& GetDesc(const Msg& msg) { return msg.desc(); } + + static void FindAndAppendExtensions(const Msg&, std::vector&) { + // type.proto does not support extensions. + } + + static size_t GetSize(Field f, const Msg& msg) { + return msg.Count(f->proto().number()); + } + + static absl::StatusOr GetFloat(Field f) { + if (f->proto().default_value().empty()) { + return 0.0; + } + float x; + if (!absl::SimpleAtof(f->proto().default_value(), &x)) { + return absl::InternalError(absl::StrCat( + "bad default value in type.proto: ", f->parent().proto().name())); + } + return x; + } + + static absl::StatusOr GetDouble(Field f) { + if (f->proto().default_value().empty()) { + return 0.0; + } + double x; + if (!absl::SimpleAtod(f->proto().default_value(), &x)) { + return absl::InternalError(absl::StrCat( + "bad default value in type.proto: ", f->parent().proto().name())); + } + return x; + } + + static absl::StatusOr GetInt32(Field f) { + if (f->proto().default_value().empty()) { + return 0; + } + int32_t x; + if (!absl::SimpleAtoi(f->proto().default_value(), &x)) { + return absl::InternalError(absl::StrCat( + "bad default value in type.proto: ", f->parent().proto().name())); + } + return x; + } + + static absl::StatusOr GetUInt32(Field f) { + if (f->proto().default_value().empty()) { + return 0; + } + uint32_t x; + if (!absl::SimpleAtoi(f->proto().default_value(), &x)) { + return absl::InternalError(absl::StrCat( + "bad default value in type.proto: ", f->parent().proto().name())); + } + return x; + } + + static absl::StatusOr GetInt64(Field f) { + if (f->proto().default_value().empty()) { + return 0; + } + int64_t x; + if (!absl::SimpleAtoi(f->proto().default_value(), &x)) { + return absl::InternalError(absl::StrCat( + "bad default value in type.proto: ", f->parent().proto().name())); + } + return x; + } + + static absl::StatusOr GetUInt64(Field f) { + if (f->proto().default_value().empty()) { + return 0; + } + uint64_t x; + if (!absl::SimpleAtoi(f->proto().default_value(), &x)) { + return absl::InternalError(absl::StrCat( + "bad default value in type.proto: ", f->parent().proto().name())); + } + return x; + } + + static absl::StatusOr GetBool(Field f) { + if (f->proto().default_value().empty()) { + return false; + } else if (f->proto().default_value() == "false") { + return false; + } else if (f->proto().default_value() == "true") { + return true; + } else { + return absl::InternalError(absl::StrCat( + "bad default value in type.proto: ", f->parent().proto().name())); + } + } + + static absl::StatusOr GetEnumValue(Field f) { + if (f->proto().default_value().empty()) { + auto e = f->EnumType(); + RETURN_IF_ERROR(e.status()); + + return (**e).proto().enumvalue(0).number(); + } + return EnumNumberByName(f, f->proto().default_value(), + /*case_insensitive=*/false); + } + + static absl::StatusOr GetString(Field f, + std::string& scratch) { + absl::CUnescape(f->proto().default_value(), &scratch); + return scratch; + } + + static absl::StatusOr GetMessage(Field f) { + return absl::InternalError("message fields cannot have defaults"); + } + + static absl::StatusOr GetFloat(Field f, const Msg& msg, + size_t idx = 0) { + return msg.Get(f->proto().number())[idx]; + } + + static absl::StatusOr GetDouble(Field f, const Msg& msg, + size_t idx = 0) { + return msg.Get(f->proto().number())[idx]; + } + + static absl::StatusOr GetInt32(Field f, const Msg& msg, + size_t idx = 0) { + return msg.Get(f->proto().number())[idx]; + } + + static absl::StatusOr GetUInt32(Field f, const Msg& msg, + size_t idx = 0) { + return msg.Get(f->proto().number())[idx]; + } + + static absl::StatusOr GetInt64(Field f, const Msg& msg, + size_t idx = 0) { + return msg.Get(f->proto().number())[idx]; + } + + static absl::StatusOr GetUInt64(Field f, const Msg& msg, + size_t idx = 0) { + return msg.Get(f->proto().number())[idx]; + } + + static absl::StatusOr GetBool(Field f, const Msg& msg, size_t idx = 0) { + return msg.Get(f->proto().number())[idx] == Msg::kTrue; + } + + static absl::StatusOr GetEnumValue(Field f, const Msg& msg, + size_t idx = 0) { + return msg.Get(f->proto().number())[idx]; + } + + static absl::StatusOr GetString(Field f, + std::string& scratch, + const Msg& msg, + size_t idx = 0) { + return msg.Get(f->proto().number())[idx]; + } + + static absl::StatusOr GetMessage(Field f, const Msg& msg, + size_t idx = 0) { + return &msg.Get(f->proto().number())[idx]; + } + + template + static absl::Status WithDecodedMessage(const Desc& desc, + absl::string_view data, F body) { + io::CodedInputStream stream(reinterpret_cast(data.data()), + data.size()); + auto unerased = Msg::ParseFromStream(&desc, stream); + RETURN_IF_ERROR(unerased.status()); + + // Explicitly create a const reference, so that we do not accidentally pass + // a mutable reference to `body`. + const Msg& ref = *unerased; + return body(ref); + } +}; +} // namespace json_internal +} // namespace protobuf +} // namespace google + +#include "google/protobuf/port_undef.inc" +#endif // GOOGLE_PROTOBUF_JSON_INTERNAL_UNPARSER_TRAITS_H__ diff --git a/src/google/protobuf/json/internal/untyped_message.cc b/src/google/protobuf/json/internal/untyped_message.cc new file mode 100644 index 0000000000..03900349ff --- /dev/null +++ b/src/google/protobuf/json/internal/untyped_message.cc @@ -0,0 +1,548 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/json/internal/untyped_message.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "google/protobuf/type.pb.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/dynamic_message.h" +#include "google/protobuf/message.h" +#include "google/protobuf/wire_format.h" +#include "google/protobuf/wire_format_lite.h" +#include "absl/container/flat_hash_map.h" +#include "absl/status/status.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "absl/types/span.h" +#include "absl/types/variant.h" +#include "google/protobuf/io/coded_stream.h" +#include "google/protobuf/util/type_resolver.h" +#include "google/protobuf/stubs/status_macros.h" + + +// Must be included last. +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace json_internal { +using ::google::protobuf::Field; +using ::google::protobuf::internal::WireFormatLite; + +absl::StatusOr ResolverPool::Field::MessageType() + const { + GOOGLE_CHECK(proto().kind() == google::protobuf::Field::TYPE_MESSAGE || + proto().kind() == google::protobuf::Field::TYPE_GROUP) + << proto().kind(); + if (type_ == nullptr) { + auto type = pool_->FindMessage(proto().type_url()); + RETURN_IF_ERROR(type.status()); + type_ = *type; + } + return reinterpret_cast(type_); +} + +absl::StatusOr ResolverPool::Field::EnumType() + const { + GOOGLE_CHECK(proto().kind() == google::protobuf::Field::TYPE_ENUM) << proto().kind(); + if (type_ == nullptr) { + auto type = pool_->FindEnum(proto().type_url()); + RETURN_IF_ERROR(type.status()); + type_ = *type; + } + return reinterpret_cast(type_); +} + +absl::Span ResolverPool::Message::FieldsByIndex() + const { + if (raw_.fields_size() > 0 && fields_ == nullptr) { + fields_ = std::unique_ptr(new Field[raw_.fields_size()]); + for (size_t i = 0; i < raw_.fields_size(); ++i) { + fields_[i].pool_ = pool_; + fields_[i].raw_ = &raw_.fields(i); + fields_[i].parent_ = this; + } + } + + return absl::MakeSpan(fields_.get(), proto().fields_size()); +} + +const ResolverPool::Field* ResolverPool::Message::FindField( + absl::string_view name) const { + if (raw_.fields_size() == 0) { + return nullptr; + } + + if (fields_by_name_.empty()) { + const Field* found = nullptr; + for (auto& field : FieldsByIndex()) { + if (field.proto().name() == name || field.proto().json_name() == name) { + found = &field; + } + fields_by_name_.try_emplace(field.proto().name(), &field); + fields_by_name_.try_emplace(field.proto().json_name(), &field); + } + return found; + } + + auto it = fields_by_name_.find(name); + return it == fields_by_name_.end() ? nullptr : it->second; +} + +const ResolverPool::Field* ResolverPool::Message::FindField( + int32_t number) const { + if (raw_.fields_size() == 0) { + return nullptr; + } + + bool is_small = raw_.fields_size() < 8; + if (is_small || fields_by_number_.empty()) { + const Field* found = nullptr; + for (auto& field : FieldsByIndex()) { + if (field.proto().number() == number) { + found = &field; + } + if (!is_small) { + fields_by_number_.try_emplace(field.proto().number(), &field); + } + } + return found; + } + + auto it = fields_by_number_.find(number); + return it == fields_by_number_.end() ? nullptr : it->second; +} + +absl::StatusOr ResolverPool::FindMessage( + absl::string_view url) { + auto it = messages_.find(url); + if (it != messages_.end()) { + return it->second.get(); + } + + auto msg = absl::WrapUnique(new Message(this)); + std::string url_buf(url); + RETURN_IF_ERROR(resolver_->ResolveMessageType(url_buf, &msg->raw_)); + + return messages_.try_emplace(std::move(url_buf), std::move(msg)) + .first->second.get(); +} + +absl::StatusOr ResolverPool::FindEnum( + absl::string_view url) { + auto it = enums_.find(url); + if (it != enums_.end()) { + return it->second.get(); + } + + auto enoom = absl::WrapUnique(new Enum(this)); + std::string url_buf(url); + RETURN_IF_ERROR(resolver_->ResolveEnumType(url_buf, &enoom->raw_)); + + return enums_.try_emplace(std::move(url_buf), std::move(enoom)) + .first->second.get(); +} + +absl::Status UntypedMessage::Decode(io::CodedInputStream& stream, + absl::optional current_group) { + while (true) { + std::vector group_stack; + uint32_t tag = stream.ReadTag(); + if (tag == 0) { + return absl::OkStatus(); + } + + int32_t field_number = tag >> 3; + int32_t wire_type = tag & 7; + + // EGROUP markers can show up as "unknown fields", so we need to handle them + // before we even do field lookup. Being inside of a group behaves as if a + // special field has been added to the message. + if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) { + if (!current_group.has_value()) { + return absl::InvalidArgumentError(absl::StrFormat( + "attempted to close group %d before SGROUP tag", field_number)); + } + if (field_number != *current_group) { + return absl::InvalidArgumentError( + absl::StrFormat("attempted to close group %d while inside group %d", + field_number, *current_group)); + } + return absl::OkStatus(); + } + + const auto* field = desc_->FindField(field_number); + if (!group_stack.empty() || field == nullptr) { + // Skip unknown field. If the group-stack is non-empty, we are in the + // process of working through an unknown group. + switch (wire_type) { + case WireFormatLite::WIRETYPE_VARINT: { + uint64_t x; + if (!stream.ReadVarint64(&x)) { + return absl::InvalidArgumentError("unexpected EOF"); + } + continue; + } + case WireFormatLite::WIRETYPE_FIXED64: { + uint64_t x; + if (!stream.ReadLittleEndian64(&x)) { + return absl::InvalidArgumentError("unexpected EOF"); + } + continue; + } + case WireFormatLite::WIRETYPE_FIXED32: { + uint32_t x; + if (!stream.ReadLittleEndian32(&x)) { + return absl::InvalidArgumentError("unexpected EOF"); + } + continue; + } + case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: { + uint32_t x; + if (!stream.ReadVarint32(&x)) { + return absl::InvalidArgumentError("unexpected EOF"); + } + stream.Skip(x); + continue; + } + case WireFormatLite::WIRETYPE_START_GROUP: { + group_stack.push_back(field_number); + continue; + } + case WireFormatLite::WIRETYPE_END_GROUP: { + if (group_stack.empty()) { + return absl::InvalidArgumentError(absl::StrFormat( + "attempted to close group %d before SGROUP tag", field_number)); + } + if (field_number != group_stack.back()) { + return absl::InvalidArgumentError(absl::StrFormat( + "attempted to close group %d while inside group %d", + field_number, *current_group)); + } + group_stack.pop_back(); + continue; + } + default: + return absl::InvalidArgumentError( + absl::StrCat("unknown wire type: ", wire_type)); + } + } + switch (wire_type) { + case WireFormatLite::WIRETYPE_VARINT: + RETURN_IF_ERROR(DecodeVarint(stream, *field)); + break; + case WireFormatLite::WIRETYPE_FIXED64: + RETURN_IF_ERROR(Decode64Bit(stream, *field)); + break; + case WireFormatLite::WIRETYPE_FIXED32: + RETURN_IF_ERROR(Decode32Bit(stream, *field)); + break; + case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: + RETURN_IF_ERROR(DecodeDelimited(stream, *field)); + break; + case WireFormatLite::WIRETYPE_START_GROUP: { + if (field->proto().kind() != Field::TYPE_GROUP) { + return absl::InvalidArgumentError(absl::StrFormat( + "field number %d is not a group", field->proto().number())); + } + auto group_desc = field->MessageType(); + RETURN_IF_ERROR(group_desc.status()); + + UntypedMessage group(*group_desc); + RETURN_IF_ERROR(group.Decode(stream, field_number)); + RETURN_IF_ERROR(InsertField(*field, std::move(group))); + break; + } + case WireFormatLite::WIRETYPE_END_GROUP: + GOOGLE_CHECK(false) << "unreachable"; + break; + default: + return absl::InvalidArgumentError( + absl::StrCat("unknown wire type: ", wire_type)); + } + } + + return absl::OkStatus(); +} + +absl::Status UntypedMessage::DecodeVarint(io::CodedInputStream& stream, + const ResolverPool::Field& field) { + switch (field.proto().kind()) { + case Field::TYPE_BOOL: { + char byte; + if (!stream.ReadRaw(&byte, 1)) { + return absl::InvalidArgumentError("unexpected EOF"); + } + switch (byte) { + case 0: + RETURN_IF_ERROR(InsertField(field, kFalse)); + break; + case 1: + RETURN_IF_ERROR(InsertField(field, kTrue)); + break; + default: + return absl::InvalidArgumentError( + absl::StrFormat("bad value for bool: \\x%02x", byte)); + } + break; + } + case Field::TYPE_INT32: + case Field::TYPE_SINT32: + case Field::TYPE_UINT32: + case Field::TYPE_ENUM: { + uint32_t x; + if (!stream.ReadVarint32(&x)) { + return absl::InvalidArgumentError("unexpected EOF"); + } + if (field.proto().kind() == Field::TYPE_UINT32) { + RETURN_IF_ERROR(InsertField(field, x)); + break; + } + if (field.proto().kind() == Field::TYPE_SINT32) { + x = WireFormatLite::ZigZagDecode32(x); + } + RETURN_IF_ERROR(InsertField(field, static_cast(x))); + break; + } + case Field::TYPE_INT64: + case Field::TYPE_SINT64: + case Field::TYPE_UINT64: { + uint64_t x; + if (!stream.ReadVarint64(&x)) { + return absl::InvalidArgumentError("unexpected EOF"); + } + if (field.proto().kind() == Field::TYPE_UINT64) { + RETURN_IF_ERROR(InsertField(field, x)); + break; + } + if (field.proto().kind() == Field::TYPE_SINT64) { + x = WireFormatLite::ZigZagDecode64(x); + } + RETURN_IF_ERROR(InsertField(field, static_cast(x))); + break; + } + default: + return absl::InvalidArgumentError(absl::StrFormat( + "field type %d (number %d) does not support varint fields", + field.proto().kind(), field.proto().number())); + } + return absl::OkStatus(); +} + +absl::Status UntypedMessage::Decode64Bit(io::CodedInputStream& stream, + const ResolverPool::Field& field) { + switch (field.proto().kind()) { + case Field::TYPE_FIXED64: { + uint64_t x; + if (!stream.ReadLittleEndian64(&x)) { + return absl::InvalidArgumentError("unexpected EOF"); + } + RETURN_IF_ERROR(InsertField(field, x)); + break; + } + case Field::TYPE_SFIXED64: { + uint64_t x; + if (!stream.ReadLittleEndian64(&x)) { + return absl::InvalidArgumentError("unexpected EOF"); + } + RETURN_IF_ERROR(InsertField(field, static_cast(x))); + break; + } + case Field::TYPE_DOUBLE: { + uint64_t x; + if (!stream.ReadLittleEndian64(&x)) { + return absl::InvalidArgumentError("unexpected EOF"); + } + RETURN_IF_ERROR(InsertField(field, absl::bit_cast(x))); + break; + } + default: + return absl::InvalidArgumentError( + absl::StrFormat("field type %d (number %d) does not support " + "type 64-bit fields", + field.proto().kind(), field.proto().number())); + } + return absl::OkStatus(); +} + +absl::Status UntypedMessage::Decode32Bit(io::CodedInputStream& stream, + const ResolverPool::Field& field) { + switch (field.proto().kind()) { + case Field::TYPE_FIXED32: { + uint32_t x; + if (!stream.ReadLittleEndian32(&x)) { + return absl::InvalidArgumentError("unexpected EOF"); + } + RETURN_IF_ERROR(InsertField(field, x)); + break; + } + case Field::TYPE_SFIXED32: { + uint32_t x; + if (!stream.ReadLittleEndian32(&x)) { + return absl::InvalidArgumentError("unexpected EOF"); + } + RETURN_IF_ERROR(InsertField(field, static_cast(x))); + break; + } + case Field::TYPE_FLOAT: { + uint32_t x; + if (!stream.ReadLittleEndian32(&x)) { + return absl::InvalidArgumentError("unexpected EOF"); + } + RETURN_IF_ERROR(InsertField(field, absl::bit_cast(x))); + break; + } + default: + return absl::InvalidArgumentError(absl::StrFormat( + "field type %d (number %d) does not support 32-bit fields", + field.proto().kind(), field.proto().number())); + } + return absl::OkStatus(); +} + +absl::Status UntypedMessage::DecodeDelimited(io::CodedInputStream& stream, + const ResolverPool::Field& field) { + auto limit = stream.ReadLengthAndPushLimit(); + if (limit == 0) { + return absl::InvalidArgumentError("unexpected EOF"); + } + + switch (field.proto().kind()) { + case Field::TYPE_STRING: + case Field::TYPE_BYTES: { + std::string buf; + if (!stream.ReadString(&buf, stream.BytesUntilLimit())) { + return absl::InvalidArgumentError("unexpected EOF"); + } + if (field.proto().kind() == Field::TYPE_STRING) { + if (desc_->proto().syntax() == google::protobuf::SYNTAX_PROTO3 && + ::google::protobuf::internal::IsStructurallyValidUTF8(buf.data(), buf.size())) { + return absl::InvalidArgumentError("proto3 strings must be UTF-8"); + } + } + + RETURN_IF_ERROR(InsertField(field, std::move(buf))); + break; + } + case Field::TYPE_MESSAGE: { + auto inner_desc = field.MessageType(); + RETURN_IF_ERROR(inner_desc.status()); + + auto inner = ParseFromStream(*inner_desc, stream); + RETURN_IF_ERROR(inner.status()); + RETURN_IF_ERROR(InsertField(field, std::move(*inner))); + break; + } + default: { + // This is definitely a packed field. + while (stream.BytesUntilLimit() > 0) { + switch (field.proto().kind()) { + case Field::TYPE_BOOL: + case Field::TYPE_INT32: + case Field::TYPE_SINT32: + case Field::TYPE_UINT32: + case Field::TYPE_ENUM: + case Field::TYPE_INT64: + case Field::TYPE_SINT64: + case Field::TYPE_UINT64: + RETURN_IF_ERROR(DecodeVarint(stream, field)); + break; + case Field::TYPE_FIXED64: + case Field::TYPE_SFIXED64: + case Field::TYPE_DOUBLE: + RETURN_IF_ERROR(Decode64Bit(stream, field)); + break; + case Field::TYPE_FIXED32: + case Field::TYPE_SFIXED32: + case Field::TYPE_FLOAT: + RETURN_IF_ERROR(Decode32Bit(stream, field)); + break; + default: + return absl::InvalidArgumentError(absl::StrFormat( + "field type %d (number %d) does not support type 2 records", + field.proto().kind(), field.proto().number())); + } + } + break; + } + } + stream.PopLimit(limit); + return absl::OkStatus(); +} + +template +absl::Status UntypedMessage::InsertField(const ResolverPool::Field& field, + T value) { + int32_t number = field.proto().number(); + auto emplace_result = fields_.try_emplace(number, std::move(value)); + if (emplace_result.second) { + return absl::OkStatus(); + } + + if (field.proto().cardinality() != + google::protobuf::Field::CARDINALITY_REPEATED) { + return absl::InvalidArgumentError( + absl::StrCat("repeated entries for singular field number ", number)); + } + + Value& slot = emplace_result.first->second; + if (auto* extant = absl::get_if(&slot)) { + std::vector repeated; + repeated.push_back(std::move(*extant)); + repeated.push_back(std::move(value)); + + slot = std::move(repeated); + } else if (auto* extant = absl::get_if>(&slot)) { + extant->push_back(std::move(value)); + } else { + return absl::InvalidArgumentError( + absl::StrFormat("inconsistent types for field number %d: tried to " + "insert %s, but index was %d", + number, typeid(T).name(), slot.index())); + } + + return absl::OkStatus(); +} + +} // namespace json_internal +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/json/internal/untyped_message.h b/src/google/protobuf/json/internal/untyped_message.h new file mode 100644 index 0000000000..1b4ad8fbaf --- /dev/null +++ b/src/google/protobuf/json/internal/untyped_message.h @@ -0,0 +1,258 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_UITL_UNTYPED_MESSAGE_H__ +#define GOOGLE_PROTOBUF_UITL_UNTYPED_MESSAGE_H__ + +#include +#include +#include +#include +#include +#include + +#include "google/protobuf/type.pb.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/dynamic_message.h" +#include "google/protobuf/message.h" +#include "google/protobuf/wire_format.h" +#include "google/protobuf/wire_format_lite.h" +#include "absl/container/flat_hash_map.h" +#include "absl/status/status.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "absl/types/span.h" +#include "absl/types/variant.h" +#include "google/protobuf/io/coded_stream.h" +#include "google/protobuf/util/type_resolver.h" +#include "google/protobuf/stubs/status_macros.h" + +// Must be included last. +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace json_internal { +struct SizeVisitor { + template + size_t operator()(const std::vector& x) { + return x.size(); + } + + template + size_t operator()(const T& x) { + return 1; + } +}; + +// A DescriptorPool-like type for caching lookups from a TypeResolver. +// +// This type and all of its nested types are thread-hostile. +class ResolverPool { + public: + class Message; + class Enum; + class Field { + public: + Field(const Field&) = delete; + Field& operator=(const Field&) = delete; + + absl::StatusOr MessageType() const; + absl::StatusOr EnumType() const; + + const Message& parent() const { return *parent_; } + const google::protobuf::Field& proto() const { return *raw_; } + + private: + friend class ResolverPool; + + Field() = default; + + ResolverPool* pool_ = nullptr; + const google::protobuf::Field* raw_ = nullptr; + const Message* parent_ = nullptr; + mutable const void* type_ = nullptr; + }; + + class Message { + public: + Message(const Message&) = delete; + Message& operator=(const Message&) = delete; + + absl::Span FieldsByIndex() const; + const Field* FindField(absl::string_view name) const; + const Field* FindField(int32_t number) const; + + const google::protobuf::Type& proto() const { return raw_; } + ResolverPool* pool() const { return pool_; } + + private: + friend class ResolverPool; + + explicit Message(ResolverPool* pool) : pool_(pool) {} + + ResolverPool* pool_; + google::protobuf::Type raw_; + mutable std::unique_ptr fields_; + mutable absl::flat_hash_map + fields_by_name_; + mutable absl::flat_hash_map fields_by_number_; + }; + + class Enum { + public: + Enum(const Enum&) = delete; + Enum& operator=(const Enum&) = delete; + + const google::protobuf::Enum& proto() const { return raw_; } + ResolverPool* pool() const { return pool_; } + + private: + friend class ResolverPool; + + explicit Enum(ResolverPool* pool) : pool_(pool) {} + + ResolverPool* pool_; + google::protobuf::Enum raw_; + mutable absl::flat_hash_map + values_; + }; + + explicit ResolverPool(google::protobuf::util::TypeResolver* resolver) + : resolver_(resolver) {} + + ResolverPool(const ResolverPool&) = delete; + ResolverPool& operator=(const ResolverPool&) = delete; + + absl::StatusOr FindMessage(absl::string_view url); + absl::StatusOr FindEnum(absl::string_view url); + + private: + absl::flat_hash_map> messages_; + absl::flat_hash_map> enums_; + google::protobuf::util::TypeResolver* resolver_; +}; + +// A parsed wire-format proto that uses TypeReslover for parsing. +// +// This type is an implementation detail of the JSON parser. +class UntypedMessage final { + public: + // New nominal type instead of `bool` to avoid vector shenanigans. + enum Bool : unsigned char { kTrue, kFalse }; + using Value = absl::variant, std::vector, + std::vector, std::vector, + std::vector, std::vector, + std::vector, std::vector, + std::vector>; + + UntypedMessage(const UntypedMessage&) = delete; + UntypedMessage& operator=(const UntypedMessage&) = delete; + UntypedMessage(UntypedMessage&&) = default; + UntypedMessage& operator=(UntypedMessage&&) = default; + + // Tries to parse a proto with the given descriptor from an input stream. + static absl::StatusOr ParseFromStream( + const ResolverPool::Message* desc, io::CodedInputStream& stream) { + UntypedMessage msg(std::move(desc)); + RETURN_IF_ERROR(msg.Decode(stream)); + return std::move(msg); + } + + // Returns the number of elements in a field by number. + // + // Optional fields are treated like repeated fields with one or zero elements. + size_t Count(int32_t field_number) const { + auto it = fields_.find(field_number); + if (it == fields_.end()) { + return 0; + } + + return absl::visit(SizeVisitor{}, it->second); + } + + // Returns the contents of a field by number. + // + // Optional fields are treated like repeated fields with one or zero elements. + // If the field is not set, returns an empty span. + // + // If `T` is the wrong type, this function crashes. + template + absl::Span Get(int32_t field_number) const { + auto it = fields_.find(field_number); + if (it == fields_.end()) { + return {}; + } + + if (auto* val = absl::get_if(&it->second)) { + return absl::Span(val, 1); + } else if (auto* vec = absl::get_if>(&it->second)) { + return *vec; + } else { + GOOGLE_CHECK(false) << "wrong type for UntypedMessage::Get(" << field_number + << ")"; + } + } + + const ResolverPool::Message& desc() const { return *desc_; } + + private: + enum Cardinality { kSingular, kRepeated }; + + explicit UntypedMessage(const ResolverPool::Message* desc) : desc_(desc) {} + + absl::Status Decode(io::CodedInputStream& stream, + absl::optional current_group = absl::nullopt); + + absl::Status DecodeVarint(io::CodedInputStream& stream, + const ResolverPool::Field& field); + absl::Status Decode64Bit(io::CodedInputStream& stream, + const ResolverPool::Field& field); + absl::Status Decode32Bit(io::CodedInputStream& stream, + const ResolverPool::Field& field); + absl::Status DecodeDelimited(io::CodedInputStream& stream, + const ResolverPool::Field& field); + + template + absl::Status InsertField(const ResolverPool::Field& field, T value); + + const ResolverPool::Message* desc_; + absl::flat_hash_map fields_; +}; +} // namespace json_internal +} // namespace protobuf +} // namespace google + +#include "google/protobuf/port_undef.inc" +#endif // GOOGLE_PROTOBUF_UITL_UNTYPED_MESSAGE_H__ diff --git a/src/google/protobuf/json/internal/writer.cc b/src/google/protobuf/json/internal/writer.cc new file mode 100644 index 0000000000..20fa3e9d04 --- /dev/null +++ b/src/google/protobuf/json/internal/writer.cc @@ -0,0 +1,329 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/json/internal/writer.h" + +#include +#include +#include +#include + +#include "google/protobuf/stubs/logging.h" +#include "google/protobuf/stubs/common.h" +#include "absl/algorithm/container.h" + +// Must be included last. +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace json_internal { + +// Tries to write a non-finite double if necessary; returns false if +// nothing was written. +bool JsonWriter::MaybeWriteSpecialFp(double val) { + if (val == std::numeric_limits::infinity()) { + Write("\"Infinity\""); + } else if (val == -std::numeric_limits::infinity()) { + Write("\"-Infinity\""); + } else if (std::isnan(val)) { + Write("\"NaN\""); + } else { + return false; + } + return true; +} + +void JsonWriter::WriteBase64(absl::string_view str) { + // This is the regular base64, not the "web-safe" version. + constexpr absl::string_view kBase64 = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + const char* ptr = str.data(); + const char* end = ptr + str.size(); + + // Reads the `n`th character off of `ptr` while gracefully avoiding + // sign extension due to implicit conversions + auto read = [&](size_t n) { + return static_cast(static_cast(ptr[n])); + }; + + char buf[4]; + absl::string_view view(buf, sizeof(buf)); + Write("\""); + + while (end - ptr >= 3) { + buf[0] = kBase64[read(0) >> 2]; + buf[1] = kBase64[((read(0) & 0x3) << 4) | (read(1) >> 4)]; + buf[2] = kBase64[((read(1) & 0xf) << 2) | (read(2) >> 6)]; + buf[3] = kBase64[read(2) & 0x3f]; + Write(view); + ptr += 3; + } + + switch (end - ptr) { + case 2: + buf[0] = kBase64[read(0) >> 2]; + buf[1] = kBase64[((read(0) & 0x3) << 4) | (read(1) >> 4)]; + buf[2] = kBase64[(read(1) & 0xf) << 2]; + buf[3] = '='; + Write(view); + break; + case 1: + buf[0] = kBase64[read(0) >> 2]; + buf[1] = kBase64[((read(0) & 0x3) << 4)]; + buf[2] = '='; + buf[3] = '='; + Write(view); + break; + } + + Write("\""); +} + +// The minimum value of a unicode high-surrogate code unit in the utf-16 +// encoding. A high-surrogate is also known as a leading-surrogate. +// See http://www.unicode.org/glossary/#high_surrogate_code_unit +static constexpr uint16_t kMinHighSurrogate = 0xd800; + +// The minimum value of a unicode low-surrogate code unit in the utf-16 +// encoding. A low-surrogate is also known as a trailing-surrogate. +// See http://www.unicode.org/glossary/#low_surrogate_code_unit +static constexpr uint16_t kMinLowSurrogate = 0xdc00; + +// The maximum value of a unicode low-surrogate code unit in the utf-16 +// encoding. A low-surrogate is also known as a trailing surrogate. +// See http://www.unicode.org/glossary/#low_surrogate_code_unit +static constexpr uint16_t kMaxLowSurrogate = 0xdfff; + +// The minimum value of a unicode supplementary code point. +// See http://www.unicode.org/glossary/#supplementary_code_point +static constexpr uint32_t kMinSupplementaryCodePoint = 0x010000; + +// The maximum value of a unicode code point. +// See http://www.unicode.org/glossary/#code_point +static constexpr uint32_t kMaxCodePoint = 0x10ffff; + +// Indicates decoding failure; not a valid Unicode scalar. +static constexpr uint32_t kErrorSentinel = 0xaaaaaaaa; + +// A Unicode Scalar encoded two ways. +struct Utf8Scalar { + // The Unicode scalar value as a 32-bit integer. If decoding failed, this + // is equal to kErrorSentinel. + uint32_t u32; + // The Unicode scalar value encoded as UTF-8 bytes. May not reflect the + // contents of `u32` if it is kErrorSentinel. + absl::string_view utf8; +}; + +// Parses a single UTF-8-encoded Unicode scalar from `str`. Returns a pair of +// the scalar and the UTF-8-encoded content corresponding to it from `str`. +// +// Returns U+FFFD on failure, and consumes an unspecified number of bytes in +// doing so. +static Utf8Scalar ConsumeUtf8Scalar(absl::string_view& str) { + GOOGLE_DCHECK(!str.empty()); + uint32_t scalar = static_cast(str[0]); + const char* start = str.data(); + size_t len = 1; + + str = str.substr(1); + + // Verify this is valid UTF-8. UTF-8 is a varint encoding satisfying + // one of the following (big-endian) patterns: + // + // 0b0xxxxxxx + // 0b110xxxxx'10xxxxxx + // 0b1110xxxx'10xxxxxx'10xxxxxx + // 0b11110xxx'10xxxxxx'10xxxxxx'10xxxxxx + // + // We don't need to decode it; just validate it. + int lookahead = 0; + switch (absl::countl_one(static_cast(scalar))) { + case 0: + break; + case 2: + lookahead = 1; + scalar &= (1 << 5) - 1; + break; + case 3: + lookahead = 2; + scalar &= (1 << 4) - 1; + break; + case 4: + lookahead = 3; + scalar &= (1 << 3) - 1; + break; + default: + scalar = kErrorSentinel; + break; + } + + for (int i = 0; i < lookahead; ++i) { + if (str.empty()) { + scalar = kErrorSentinel; + break; + } + + uint8_t next = str[0]; + str = str.substr(1); + ++len; + + // Looking for top 2 bits are 0b10. + if (next >> 6 != 2) { + scalar = kErrorSentinel; + break; + } + next &= (1 << 6) - 1; + scalar <<= 6; + scalar |= next; + } + + if (scalar > kMaxCodePoint) { + scalar = kErrorSentinel; + } + + return {scalar, absl::string_view(start, len)}; +} + +// Decides whether we must escape `scalar`. +// +// If the given Unicode scalar would not use a \u escape, `custom_escape` will +// be set to a non-empty string. +static bool MustEscape(uint32_t scalar, absl::string_view& custom_escape) { + switch (scalar) { + // These escapes are defined by the JSON spec. We do not escape /. + case '\n': + custom_escape = R"(\n)"; + return true; + case '\r': + custom_escape = R"(\r)"; + return true; + case '\t': + custom_escape = R"(\t)"; + return true; + case '\"': + custom_escape = R"(\")"; + return true; + case '\f': + custom_escape = R"(\f)"; + return true; + case '\b': + custom_escape = R"(\b)"; + return true; + case '\\': + custom_escape = R"(\\)"; + return true; + + case kErrorSentinel: + // Decoding failure turns into spaces, *not* replacement characters. We + // handle this separately from "normal" spaces so that it follows the + // escaping code-path. + // + // Note that literal replacement characters in the input string DO NOT + // get turned into spaces; this is only for decoding failures! + custom_escape = " "; + return true; + + // These are not required by the JSON spec, but help + // to prevent security bugs in JavaScript. + // + // These were originally present in the ESF parser, so they are kept for + // legacy compatibility (and because escaping most of these is in good + // taste, regardless). + case '<': + case '>': + case 0xfeff: // Zero width no-break space. + case 0xfff9: // Interlinear annotation anchor. + case 0xfffa: // Interlinear annotation separator. + case 0xfffb: // Interlinear annotation terminator. + case 0x00ad: // Soft-hyphen. + case 0x06dd: // Arabic end of ayah. + case 0x070f: // Syriac abbreviation mark. + case 0x17b4: // Khmer vowel inherent Aq. + case 0x17b5: // Khmer vowel inherent Aa. + case 0x000e0001: // Language tag. + return true; + default: + static constexpr std::pair kEscapedRanges[] = { + {0x0000, 0x001f}, // ASCII control. + {0x007f, 0x009f}, // High ASCII bytes. + {0x0600, 0x0603}, // Arabic signs. + {0x200b, 0x200f}, // Zero width etc. + {0x2028, 0x202e}, // Separators etc. + {0x2060, 0x2064}, // Invisible etc. + {0x206a, 0x206f}, // Shaping etc. + {0x0001d173, 0x0001d17a}, // Music formatting. + {0x000e0020, 0x000e007f}, // TAG symbols. + }; + + return absl::c_any_of(kEscapedRanges, [scalar](auto range) { + return range.first <= scalar && scalar <= range.second; + }); + } +} + +void JsonWriter::WriteEscapedUtf8(absl::string_view str) { + while (!str.empty()) { + auto scalar = ConsumeUtf8Scalar(str); + absl::string_view custom_escape; + + if (!MustEscape(scalar.u32, custom_escape)) { + Write(scalar.utf8); + continue; + } + + if (!custom_escape.empty()) { + Write(custom_escape); + continue; + } + + if (scalar.u32 < 0x10000) { + WriteUEscape(scalar.u32); + continue; + } + + uint16_t lo = + (scalar.u32 & (kMaxLowSurrogate - kMinLowSurrogate)) + kMinLowSurrogate; + uint16_t hi = (scalar.u32 >> 10) + + (kMinHighSurrogate - (kMinSupplementaryCodePoint >> 10)); + WriteUEscape(hi); + WriteUEscape(lo); + } +} + +void JsonWriter::WriteUEscape(uint16_t val) { + char hex[7]; + int len = absl::SNPrintF(hex, sizeof(hex), R"(\u%04x)", val); + Write(absl::string_view(hex, static_cast(len))); +} +} // namespace json_internal +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/json/internal/writer.h b/src/google/protobuf/json/internal/writer.h new file mode 100644 index 0000000000..8e0c8aa8a9 --- /dev/null +++ b/src/google/protobuf/json/internal/writer.h @@ -0,0 +1,239 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_JSON_INTERNAL_WRITER_H__ +#define GOOGLE_PROTOBUF_JSON_INTERNAL_WRITER_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "google/protobuf/stubs/strutil.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" +#include "google/protobuf/io/zero_copy_sink.h" +#include "google/protobuf/io/zero_copy_stream.h" +#include "google/protobuf/stubs/status_macros.h" + +// Must be included last. +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace json_internal { +struct WriterOptions { + // Whether to add spaces, line breaks and indentation to make the JSON output + // easy to read. + bool add_whitespace = false; + // Whether to always print primitive fields. By default proto3 primitive + // fields with default values will be omitted in JSON output. For example, an + // int32 field set to 0 will be omitted. Set this flag to true will override + // the default behavior and print primitive fields regardless of their values. + bool always_print_primitive_fields = false; + // Whether to always print enums as ints. By default they are rendered as + // strings. + bool always_print_enums_as_ints = false; + // Whether to preserve proto field names + bool preserve_proto_field_names = false; + // The original parser used by json_util2 accepted a number of non-standard + // options. Setting this flag enables them. + // + // What those extensions were is explicitly not documented, beyond what exists + // in the unit tests; we intend to remove this setting eventually. See + // b/234868512. + bool allow_legacy_syntax = false; +}; + +template +void EachInner(const Tuple& value, F f, std::index_sequence) { + (void)(int[]){(f(std::get(value)), 0)...}; // NOLINT(readability/braces) +} + +// Executes f on each element of value. +template +void Each(const Tuple& value, F f) { + EachInner(value, f, + std::make_index_sequence::value>()); +} + +// See JsonWriter::Write(). +template +struct Quoted { + std::tuple value; +}; + +// Because this is not C++17 yet, we cannot add a deduction guide. +template +static Quoted MakeQuoted(T... t) { + return Quoted{std::make_tuple(t...)}; +} + +class JsonWriter { + public: + JsonWriter(io::ZeroCopyOutputStream* out, WriterOptions options) + : sink_(out), options_(options) {} + + const WriterOptions& options() const { return options_; } + + void Push() { ++indent_; } + void Pop() { --indent_; } + + // The many overloads of Write() will write a value to the underlying stream. + // Some values may want to be quoted; the Quoted<> type will automatically add + // quotes and escape sequences. + // + // Note that Write() is not implemented for 64-bit integers, since they + // cannot be crisply represented without quotes; use MakeQuoted for that. + + void Write(absl::string_view str) { sink_.Append(str.data(), str.size()); } + + void Write(char c) { sink_.Append(&c, 1); } + + // The precision on this and the following function are completely made-up, + // in an attempt to match the behavior of the ESF parser. + void Write(double val) { + if (!MaybeWriteSpecialFp(val)) { + Write(SimpleDtoa(val)); + } + } + + void Write(float val) { + if (!MaybeWriteSpecialFp(val)) { + Write(SimpleFtoa(val)); + } + } + + void Write(int32_t val) { + char buf[22]; + int len = absl::SNPrintF(buf, sizeof(buf), "%d", val); + absl::string_view view(buf, static_cast(len)); + Write(view); + } + + void Write(uint32_t val) { + char buf[22]; + int len = absl::SNPrintF(buf, sizeof(buf), "%d", val); + absl::string_view view(buf, static_cast(len)); + Write(view); + } + + void Write(int64_t) = delete; + void Write(uint64_t) = delete; + + template + void Write(Quoted val) { + Write('"'); + Each(val.value, [this](auto x) { WriteQuoted(x); }); + Write('"'); + } + + template + auto Write(Ts... args) -> + // This bit of SFINAE avoids this function being called with one argument, + // so the other overloads of Write() can be picked up instead. + typename std::enable_if::type { + Each(std::make_tuple(args...), [this](auto x) { Write(x); }); + } + + void Whitespace(absl::string_view ws) { + if (options_.add_whitespace) { + Write(ws); + } + } + + void NewLine() { + Whitespace("\n"); + for (int i = 0; i < indent_; ++i) { + Whitespace(" "); + } + } + + void WriteComma(bool& is_first) { + if (is_first) { + is_first = false; + return; + } + Write(","); + } + + void WriteBase64(absl::string_view str); + + // Returns a buffer that can be re-used throughout a writing session as + // variable-length scratch space. + std::string& ScratchBuf() { return scratch_buf_; } + + private: + template + void WriteQuoted(T val) { + Write(val); + } + + void WriteQuoted(absl::string_view val) { WriteEscapedUtf8(val); } + + void WriteQuoted(int64_t val) { + char buf[22]; + int len = absl::SNPrintF(buf, sizeof(buf), "%d", val); + absl::string_view view(buf, static_cast(len)); + Write(view); + } + + void WriteQuoted(uint64_t val) { + char buf[22]; + int len = absl::SNPrintF(buf, sizeof(buf), "%d", val); + absl::string_view view(buf, static_cast(len)); + Write(view); + } + + // Tries to write a non-finite double if necessary; returns false if + // nothing was written. + bool MaybeWriteSpecialFp(double val); + + void WriteEscapedUtf8(absl::string_view str); + void WriteUEscape(uint16_t val); + + io::zc_sink_internal::ZeroCopyStreamByteSink sink_; + WriterOptions options_; + int indent_ = 0; + + std::string scratch_buf_; +}; +} // namespace json_internal +} // namespace protobuf +} // namespace google + +#include "google/protobuf/port_undef.inc" +#endif // GOOGLE_PROTOBUF_JSON_INTERNAL_WRITER_H__ diff --git a/src/google/protobuf/json/internal/zero_copy_buffered_stream.cc b/src/google/protobuf/json/internal/zero_copy_buffered_stream.cc new file mode 100644 index 0000000000..9801ed2946 --- /dev/null +++ b/src/google/protobuf/json/internal/zero_copy_buffered_stream.cc @@ -0,0 +1,148 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/json/internal/zero_copy_buffered_stream.h" + +#include +#include +#include +#include + +#include "absl/algorithm/container.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" +#include "google/protobuf/stubs/status_macros.h" + +// Must be included last. +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace json_internal { +absl::Status ZeroCopyBufferedStream::Advance(size_t bytes) { + while (bytes != 0) { + if (Unread().empty() && !ReadChunk()) { + return absl::InvalidArgumentError("unexpected EOF"); + } + size_t to_skip = std::min(bytes, Unread().size()); + cursor_ += to_skip; + bytes -= to_skip; + } + + if (using_buf_) { + GOOGLE_DCHECK_LE(cursor_, buffer_start_ + buf_.size()); + } else { + GOOGLE_DCHECK_LE(cursor_, last_chunk_.size()); + } + + return absl::OkStatus(); +} + +absl::StatusOr ZeroCopyBufferedStream::BufferAtLeast( + size_t bytes) { + // This MUST be an empty guard before the first call to ReadChunk(); + // otherwise we risk unconditional buffering. + BufferingGuard guard; + while (Unread().size() < bytes) { + if (!Unread().empty()) { + // We must buffer before reading if Unread() is nonempty; otherwise we + // risk discarding part of the unread buffer. However, we must NOT + // buffer before calling ReadChunk if it *is* empty, because then we + // would buffer unconditionally. + // + // There are tests to verify both of these cases. + guard = BufferingGuard(this); + } + if (!ReadChunk()) { + return absl::InvalidArgumentError("unexpected EOF"); + } + guard = BufferingGuard(this); + } + GOOGLE_DCHECK_GE(Unread().size(), bytes); + return BufferingGuard(this); +} + +void ZeroCopyBufferedStream::DownRefBuffer() { + GOOGLE_DCHECK_GT(outstanding_buffer_borrows_, 0); + + --outstanding_buffer_borrows_; + if (outstanding_buffer_borrows_ > 0 || !using_buf_) { + return; + } + + // The "virtual length" is the size of the buffer cursor_ indexes into, which + // is bigger than buf_. + size_t virtual_buf_len = buf_.size() + buffer_start_; + size_t last_chunk_in_buf = virtual_buf_len - last_chunk_.size(); + // If we are inside of `last_chunk_`, set the cursor there; otherwise, we have + // a dangling reference somewhere. + GOOGLE_DCHECK_LE(last_chunk_in_buf, virtual_buf_len) << absl::StrFormat( + "%d, %d, %d", buf_.size(), last_chunk_.size(), buffer_start_); + if (cursor_ <= last_chunk_in_buf) { + cursor_ = 0; + } else { + cursor_ -= last_chunk_in_buf; + } + buf_.clear(); + using_buf_ = false; +} + +bool ZeroCopyBufferedStream::ReadChunk() { + if (eof_) { + return false; + } + // We are buffering a second chunk, so we need to put the current chunk + // into the buffer. + if (outstanding_buffer_borrows_ > 0 && !using_buf_) { + absl::c_copy(RawBuffer(buffer_start_), std::back_inserter(buf_)); + using_buf_ = true; + } + + const void* data; + int len; + if (!stream_->Next(&data, &len)) { + eof_ = true; + return false; + } + + last_chunk_ = absl::string_view(static_cast(data), + static_cast(len)); + if (using_buf_) { + absl::c_copy(last_chunk_, std::back_inserter(buf_)); + // Cursor does not need to move, because it is still inside of `buf_`. + } else { + cursor_ = 0; + buffer_start_ = 0; + } + return true; +} +} // namespace json_internal +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/json/internal/zero_copy_buffered_stream.h b/src/google/protobuf/json/internal/zero_copy_buffered_stream.h new file mode 100644 index 0000000000..dc081e098c --- /dev/null +++ b/src/google/protobuf/json/internal/zero_copy_buffered_stream.h @@ -0,0 +1,355 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_JSON_INTERNAL_ZERO_COPY_BUFFERED_STREAM_H__ +#define GOOGLE_PROTOBUF_JSON_INTERNAL_ZERO_COPY_BUFFERED_STREAM_H__ + +#include +#include +#include +#include +#include +#include + +#include "google/protobuf/stubs/logging.h" +#include "google/protobuf/stubs/common.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" +#include "google/protobuf/io/zero_copy_stream.h" +#include "google/protobuf/stubs/status_macros.h" + +// Must be included last. +#include "google/protobuf/port_def.inc" + +// Utilities for parsing contiguous buffers out of ZeroCopyInputStreams. + +namespace google { +namespace protobuf { +namespace json_internal { +// Forward decl. for use by helper types below. +class ZeroCopyBufferedStream; + +// An RAII type that represents holding a reference into the backing buffer +// of a ZeroCopyBufferedStream. This allows for automatic management of the +// backing buffer. +class BufferingGuard { + public: + explicit BufferingGuard(ZeroCopyBufferedStream* owner = nullptr); + ~BufferingGuard(); + + BufferingGuard(const BufferingGuard& other) : BufferingGuard(other.owner_) {} + BufferingGuard& operator=(const BufferingGuard& other) { + this->~BufferingGuard(); + new (this) BufferingGuard(other); + return *this; + } + + private: + friend class Mark; + ZeroCopyBufferedStream* owner_ = nullptr; +}; + +// A string that may own its contents, or live inside of a buffer owned by +// a ZeroCopyBufferedStream. +// +// Note that this type holds onto a reference to the owning +// ZeroCopyBufferedStream; this allows it to be durable against strings being +// moved around for buffering puroses. +class MaybeOwnedString { + public: + explicit MaybeOwnedString(std::string value) : data_(std::move(value)) {} + MaybeOwnedString(ZeroCopyBufferedStream* stream, size_t start, size_t len, + BufferingGuard token) + : data_(StreamOwned{stream, start, len}), token_(token) {} + + // Returns the string as a view, regardless of whether it is owned or not. + absl::string_view AsView() const { + if (auto* unowned = absl::get_if(&data_)) { + return unowned->AsView(); + } + + return absl::get(data_); + } + + operator absl::string_view() const { return AsView(); } // NOLINT + + // Returns a reference to an owned string; if the wrapped string is not + // owned, this function will perform a copy and make it owned. + std::string& ToString() { + if (auto* unowned = absl::get_if(&data_)) { + data_ = std::string(unowned->AsView()); + token_ = BufferingGuard{}; + } + + return absl::get(data_); + } + + template + friend bool operator==(const MaybeOwnedString& lhs, const String& rhs) { + return lhs.AsView() == rhs; + } + template + friend bool operator!=(const MaybeOwnedString& lhs, const String& rhs) { + return !(lhs == rhs); + } + + private: + struct StreamOwned { + ZeroCopyBufferedStream* stream; + size_t start, len; + absl::string_view AsView() const; + }; + absl::variant data_; + BufferingGuard token_; +}; + +// A mark in a stream. See ZeroCopyBufferedStream::Mark(). +class Mark { + public: + // Returns a maybe-owned string up to the unread bytes boundary, except for + // the last `clip` bytes. + MaybeOwnedString UpToUnread(size_t clip = 0) const; + + // Discards this mark and its hold on the buffer. + void Discard() && { guard_ = BufferingGuard(); } + + private: + friend ZeroCopyBufferedStream; + Mark(size_t offset, BufferingGuard guard) : offset_(offset), guard_(guard) {} + + size_t offset_; + BufferingGuard guard_; +}; + +// A wrapper over a ZeroCopyInputStream that allows doing as-needed buffer for +// obtaining contiguous chunks larger than those the underlying stream might +// provide, while minimizing the amount of actual copying. +class ZeroCopyBufferedStream { + public: + explicit ZeroCopyBufferedStream(io::ZeroCopyInputStream* stream) + : stream_(stream) {} + + // Returns whether the stream is currently at eof. + // + // This function will buffer at least one character to verify whether it + // actually *is* at EOF. + bool AtEof() { + (void)BufferAtLeast(1); + return eof_; + } + + // Takes exactly n characters from a string. + absl::StatusOr Take(size_t len) { + auto buffering = BufferAtLeast(len); + RETURN_IF_ERROR(buffering.status()); + + size_t start = cursor_; + RETURN_IF_ERROR(Advance(len)); + return MaybeOwnedString(this, start, len, *buffering); + } + + // Takes characters to form a string, according to the given predicate. Stops + // early if an EOF is hit. + // + // The predicate must have type `(int, char) -> bool`; the first argument + // is the index of the character. + template + absl::StatusOr TakeWhile(Pred p); + + // Places a mark in the stream, ensuring that all characters consumed after + // the mark are buffered. This can be used to parse some characters and then + // recover everything that follows as a contiguous string_view so that it may + // be processed a second time. + // + // The returned value is an RAII type that ensure the buffer sticks around + // long enough. + Mark BeginMark() { return Mark(cursor_, BufferingGuard(this)); } + + // Peeks the next character in the stream. + // + // This function will not enable buffering on its own, and will read past the + // end of the buffer if at EOF; BufferAtLeast() should be called before + // calling this function. + char PeekChar() { + GOOGLE_DCHECK(!Unread().empty()); + return Unread()[0]; + } + + // Advances the cursor by the given number of bytes. + absl::Status Advance(size_t bytes); + + // Returns a view of the current buffer, which may be either the owned + // `buf_` or the stream-owned `last_chunk_`. + // + // The returned view is unstable: calling any function may invalidate it, + // because there will not be a `BufferingGuard` to guard it. + absl::string_view RawBuffer(size_t start, + size_t len = absl::string_view::npos) const; + + // Returns a view of RawBuffer, unread bytes; this will not be the entirety + // of the underlying stream. + absl::string_view Unread() const { return RawBuffer(cursor_); } + + bool IsBuffering() const { return using_buf_; } + + // Buffers at least `bytes` bytes ahead of the current cursor position, + // possibly enabling buffering. + // + // Returns an error if that many bytes could not be RawBuffer. + absl::StatusOr BufferAtLeast(size_t bytes); + + private: + friend BufferingGuard; + friend Mark; + friend MaybeOwnedString; + + // Increments the buffering refcount; this will also update `buffer_start_` if + // necessary. + void UpRefBuffer() { + if (outstanding_buffer_borrows_++ == 0) { + buffer_start_ = cursor_; + } + } + + // Decrements the buffering refcount; calling this function if the refcount is + // zero is undefined behavior. + // + // This function should not be called directly; it is called automatically + // by the destructor of `BufferingGuard`. + void DownRefBuffer(); + + // Obtains a new chunk from the underlying stream; returns whether there is + // still more data to read. + bool ReadChunk(); + + // The streamer implements a buffering stream on top of the given stream, by + // the following mechanism: + // - `cursor_` is an offset into either `last_chunk_` or `buf_`, which can + // be obtained via RawBuffer() and Unread(): + // - If `using_buf_` is true, it is an offset into `buf_`. + // - Otherwise it is an offset into `last_chunk_`. + // - If `outstanding_buffer_borrows_ > 0`, someone needs the buffer to stick + // around. MaybeUnownedString::StreamOwned is implemented such that it does + // not hold onto `last_chunk_` directly, so we can freely copy it into + // `buf_` as needed arises. + // - Note that we can copy only part if we update `buffer_start_`; see + // RawBuffer(). + // - If we would read more data and `outstanding_buffer_borrows_ > 0`, instead + // of trashing `last_chunk_`, we copy it into `buf_` and append to `buf_` + // each time we read. + // - If `outstanding_buffer_borrows_ == 0`, we can trash `buf_` and go back to + // using `last_chunk_` directly. See `DownRefBuffer()`. + io::ZeroCopyInputStream* stream_; + absl::string_view last_chunk_; + std::vector buf_; + bool using_buf_ = false; + size_t cursor_ = 0; + // Invariant: this always refers to the earliest point at which we requested + // buffering, since the last time outstanding_buffer_borrows_ was zero. + size_t buffer_start_ = 0; + bool eof_ = false; + int outstanding_buffer_borrows_ = 0; +}; + +// These functions all rely on the definition of ZeroCopyBufferedStream, so must +// come after it. +inline BufferingGuard::BufferingGuard(ZeroCopyBufferedStream* owner) + : owner_(owner) { + if (owner_ != nullptr) { + owner_->UpRefBuffer(); + } +} + +inline BufferingGuard::~BufferingGuard() { + if (owner_ != nullptr) { + owner_->DownRefBuffer(); + owner_ = nullptr; + } +} + +inline absl::string_view MaybeOwnedString::StreamOwned::AsView() const { + return stream->RawBuffer(start, len); +} + +inline MaybeOwnedString Mark::UpToUnread(size_t clip) const { + return MaybeOwnedString(guard_.owner_, offset_, + guard_.owner_->cursor_ - offset_ - clip, guard_); +} + +template +absl::StatusOr ZeroCopyBufferedStream::TakeWhile(Pred p) { + size_t start = cursor_; + BufferingGuard guard(this); + while (true) { + if (!BufferAtLeast(1).ok()) { + // We treat EOF as ending the take, rather than being an error. + break; + } + if (!p(cursor_ - start, PeekChar())) { + break; + } + RETURN_IF_ERROR(Advance(1)); + } + + return MaybeOwnedString(this, start, cursor_ - start, guard); +} + +inline absl::string_view ZeroCopyBufferedStream::RawBuffer(size_t start, + size_t len) const { + absl::string_view view = last_chunk_; + if (using_buf_) { + GOOGLE_DCHECK_LE(buffer_start_, start); + start -= buffer_start_; + view = absl::string_view(buf_.data(), buf_.size()); + } +#if 0 + // This print statement is especially useful for trouble-shooting low-level + // bugs in the buffering logic. + GOOGLE_LOG(INFO) << absl::StreamFormat("%s(\"%s\")[%d:%d]/%d:%d @ %p", + using_buf_ ? "buf_" : "last_chunk_", + view, start, static_cast(len), + buffer_start_, cursor_, this); +#endif + GOOGLE_DCHECK_LE(start, view.size()); + if (len == absl::string_view::npos) { + return view.substr(start); + } + + GOOGLE_DCHECK_LE(start + len, view.size()); + return view.substr(start, len); +} +} // namespace json_internal +} // namespace protobuf +} // namespace google + +#include "google/protobuf/port_undef.inc" +#endif // GOOGLE_PROTOBUF_JSON_INTERNAL_ZERO_COPY_BUFFERED_STREAM_H__ diff --git a/src/google/protobuf/json/internal/zero_copy_buffered_stream_test.cc b/src/google/protobuf/json/internal/zero_copy_buffered_stream_test.cc new file mode 100644 index 0000000000..714062ebaf --- /dev/null +++ b/src/google/protobuf/json/internal/zero_copy_buffered_stream_test.cc @@ -0,0 +1,165 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/json/internal/zero_copy_buffered_stream.h" + +#include +#include +#include + +#include "google/protobuf/stubs/logging.h" +#include "google/protobuf/stubs/common.h" +#include +#include +#include "absl/strings/string_view.h" +#include "google/protobuf/json/internal/test_input_stream.h" +#include "google/protobuf/stubs/status_macros.h" + +namespace google { +namespace protobuf { +namespace json_internal { +namespace { +// TODO(b/234474291): Use the gtest versions once that's available in OSS. +MATCHER_P(IsOkAndHolds, inner, + absl::StrCat("is OK and holds ", testing::PrintToString(inner))) { + if (!arg.ok()) { + *result_listener << arg.status(); + return false; + } + return testing::ExplainMatchResult(inner, *arg, result_listener); +} + +absl::Status GetStatus(const absl::Status& s) { return s; } +template +absl::Status GetStatus(const absl::StatusOr& s) { + return s.status(); +} + +MATCHER_P(StatusIs, status, + absl::StrCat(".status() is ", testing::PrintToString(status))) { + return GetStatus(arg).code() == status; +} + +#define EXPECT_OK(x) EXPECT_THAT(x, StatusIs(absl::StatusCode::kOk)) +#define ASSERT_OK(x) ASSERT_THAT(x, StatusIs(absl::StatusCode::kOk)) + +TEST(ZcBufferTest, ReadUnbuffered) { + TestInputStream in{"foo", "bar", "baz"}; + ZeroCopyBufferedStream stream(&in); + + { + auto chunk = stream.Take(3); + EXPECT_FALSE(stream.IsBuffering()); + EXPECT_THAT(chunk, IsOkAndHolds("foo")); + } + + { + auto chunk = stream.Take(3); + EXPECT_FALSE(stream.IsBuffering()); + EXPECT_THAT(chunk, IsOkAndHolds("bar")); + } + + { + auto chunk = stream.Take(3); + EXPECT_FALSE(stream.IsBuffering()); + EXPECT_THAT(chunk, IsOkAndHolds("baz")); + } +} + +TEST(ZcBufferTest, ReadBuffered) { + TestInputStream in{"foo", "bar", "baz"}; + ZeroCopyBufferedStream stream(&in); + + { + auto chunk = stream.Take(4); + EXPECT_TRUE(stream.IsBuffering()); + EXPECT_THAT(chunk, IsOkAndHolds("foob")); + } + + { + auto chunk = stream.Take(2); + EXPECT_FALSE(stream.IsBuffering()); + EXPECT_THAT(chunk, IsOkAndHolds("ar")); + } +} + +TEST(ZcBufferTest, HoldAcrossSeam) { + TestInputStream in{"foo", "bar", "baz"}; + ZeroCopyBufferedStream stream(&in); + + auto chunk = stream.Take(3); + EXPECT_FALSE(stream.IsBuffering()); + EXPECT_THAT(chunk, IsOkAndHolds("foo")); + + auto chunk2 = stream.Take(3); + EXPECT_TRUE(stream.IsBuffering()); + EXPECT_THAT(chunk2, IsOkAndHolds("bar")); + EXPECT_THAT(chunk, IsOkAndHolds("foo")); +} + +TEST(ZcBufferTest, BufferAcrossSeam) { + TestInputStream in{"foo", "bar", "baz"}; + ZeroCopyBufferedStream stream(&in); + + auto chunk = stream.Take(2); + EXPECT_FALSE(stream.IsBuffering()); + EXPECT_THAT(chunk, IsOkAndHolds("fo")); + + auto chunk2 = stream.Take(3); + EXPECT_TRUE(stream.IsBuffering()); + EXPECT_THAT(chunk2, IsOkAndHolds("oba")); + EXPECT_THAT(chunk, IsOkAndHolds("fo")); +} + +TEST(ZcBufferTest, MarkUnbuffered) { + TestInputStream in{"foo", "bar", "baz"}; + ZeroCopyBufferedStream stream(&in); + + ASSERT_OK(stream.Advance(1)); + auto mark = stream.BeginMark(); + ASSERT_OK(stream.Advance(2)); + EXPECT_FALSE(stream.IsBuffering()); + EXPECT_THAT(mark.UpToUnread(), "oo"); +} + +TEST(ZcBufferTest, MarkBuffered) { + TestInputStream in{"foo", "bar", "baz"}; + ZeroCopyBufferedStream stream(&in); + + ASSERT_OK(stream.Advance(1)); + auto mark = stream.BeginMark(); + ASSERT_OK(stream.Advance(5)); + EXPECT_TRUE(stream.IsBuffering()); + EXPECT_THAT(mark.UpToUnread(), "oobar"); +} +} // namespace +} // namespace json_internal +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/json/json.cc b/src/google/protobuf/json/json.cc new file mode 100644 index 0000000000..ba6b3af868 --- /dev/null +++ b/src/google/protobuf/json/json.cc @@ -0,0 +1,134 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/json/json.h" + +#include + +#include "absl/status/status.h" +#include "absl/strings/string_view.h" +#include "google/protobuf/io/zero_copy_stream.h" +#include "google/protobuf/json/internal/parser.h" +#include "google/protobuf/json/internal/unparser.h" +#include "google/protobuf/util/type_resolver.h" +#include "google/protobuf/stubs/status_macros.h" + + +// Must be included last. +#include "google/protobuf/port_def.inc" + + +namespace google { +namespace protobuf { +namespace json { +absl::Status BinaryToJsonStream(google::protobuf::util::TypeResolver* resolver, + const std::string& type_url, + io::ZeroCopyInputStream* binary_input, + io::ZeroCopyOutputStream* json_output, + const PrintOptions& options) { + google::protobuf::json_internal::WriterOptions opts; + opts.add_whitespace = options.add_whitespace; + opts.preserve_proto_field_names = options.preserve_proto_field_names; + opts.always_print_enums_as_ints = options.always_print_enums_as_ints; + opts.always_print_primitive_fields = options.always_print_primitive_fields; + + // TODO(b/234868512): Drop this setting. + opts.allow_legacy_syntax = true; + + return google::protobuf::json_internal::BinaryToJsonStream( + resolver, type_url, binary_input, json_output, opts); +} + +absl::Status BinaryToJsonString(google::protobuf::util::TypeResolver* resolver, + const std::string& type_url, + const std::string& binary_input, + std::string* json_output, + const PrintOptions& options) { + io::ArrayInputStream input_stream(binary_input.data(), binary_input.size()); + io::StringOutputStream output_stream(json_output); + return BinaryToJsonStream(resolver, type_url, &input_stream, &output_stream, + options); +} + +absl::Status JsonToBinaryStream(google::protobuf::util::TypeResolver* resolver, + const std::string& type_url, + io::ZeroCopyInputStream* json_input, + io::ZeroCopyOutputStream* binary_output, + const ParseOptions& options) { + google::protobuf::json_internal::ParseOptions opts; + opts.ignore_unknown_fields = options.ignore_unknown_fields; + opts.case_insensitive_enum_parsing = options.case_insensitive_enum_parsing; + + // TODO(b/234868512): Drop this setting. + opts.allow_legacy_syntax = true; + + return google::protobuf::json_internal::JsonToBinaryStream( + resolver, type_url, json_input, binary_output, opts); +} + +absl::Status JsonToBinaryString(google::protobuf::util::TypeResolver* resolver, + const std::string& type_url, + absl::string_view json_input, + std::string* binary_output, + const ParseOptions& options) { + io::ArrayInputStream input_stream(json_input.data(), json_input.size()); + io::StringOutputStream output_stream(binary_output); + return JsonToBinaryStream(resolver, type_url, &input_stream, &output_stream, + options); +} + +absl::Status MessageToJsonString(const Message& message, std::string* output, + const PrintOptions& options) { + google::protobuf::json_internal::WriterOptions opts; + opts.add_whitespace = options.add_whitespace; + opts.preserve_proto_field_names = options.preserve_proto_field_names; + opts.always_print_enums_as_ints = options.always_print_enums_as_ints; + opts.always_print_primitive_fields = options.always_print_primitive_fields; + + // TODO(b/234868512): Drop this setting. + opts.allow_legacy_syntax = true; + + return google::protobuf::json_internal::MessageToJsonString(message, output, opts); +} + +absl::Status JsonStringToMessage(absl::string_view input, Message* message, + const ParseOptions& options) { + google::protobuf::json_internal::ParseOptions opts; + opts.ignore_unknown_fields = options.ignore_unknown_fields; + opts.case_insensitive_enum_parsing = options.case_insensitive_enum_parsing; + + // TODO(b/234868512): Drop this setting. + opts.allow_legacy_syntax = true; + + return google::protobuf::json_internal::JsonStringToMessage(input, message, opts); +} +} // namespace json +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/json/json.h b/src/google/protobuf/json/json.h new file mode 100644 index 0000000000..531de6b273 --- /dev/null +++ b/src/google/protobuf/json/json.h @@ -0,0 +1,190 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Utility functions to convert between protobuf binary format and proto3 JSON +// format. +#ifndef GOOGLE_PROTOBUF_JSON_JSON_H__ +#define GOOGLE_PROTOBUF_JSON_JSON_H__ + +#include + +#include "absl/status/status.h" +#include "absl/strings/string_view.h" +#include "google/protobuf/message.h" +#include "google/protobuf/util/type_resolver.h" + +// Must be included last. +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace json { +struct ParseOptions { + // Whether to ignore unknown JSON fields during parsing + bool ignore_unknown_fields = false; + + // If true, when a lowercase enum value fails to parse, try convert it to + // UPPER_CASE and see if it matches a valid enum. + // WARNING: This option exists only to preserve legacy behavior. Avoid using + // this option. If your enum needs to support different casing, consider using + // allow_alias instead. + bool case_insensitive_enum_parsing = false; + + ParseOptions() + : ignore_unknown_fields(false), case_insensitive_enum_parsing(false) {} +}; + +struct PrintOptions { + // Whether to add spaces, line breaks and indentation to make the JSON output + // easy to read. + bool add_whitespace = false; + // Whether to always print primitive fields. By default proto3 primitive + // fields with default values will be omitted in JSON output. For example, an + // int32 field set to 0 will be omitted. Set this flag to true will override + // the default behavior and print primitive fields regardless of their values. + bool always_print_primitive_fields = false; + // Whether to always print enums as ints. By default they are rendered as + // strings. + bool always_print_enums_as_ints = false; + // Whether to preserve proto field names + bool preserve_proto_field_names = false; + + PrintOptions() + : add_whitespace(false), + always_print_primitive_fields(false), + always_print_enums_as_ints(false), + preserve_proto_field_names(false) {} +}; + +// Converts from protobuf message to JSON and appends it to |output|. This is a +// simple wrapper of BinaryToJsonString(). It will use the DescriptorPool of the +// passed-in message to resolve Any types. +// +// Please note that non-OK statuses are not a stable output of this API and +// subject to change without notice. +PROTOBUF_EXPORT absl::Status MessageToJsonString(const Message& message, + std::string* output, + const PrintOptions& options); + +inline absl::Status MessageToJsonString(const Message& message, + std::string* output) { + return MessageToJsonString(message, output, PrintOptions()); +} + +// Converts from JSON to protobuf message. This is a simple wrapper of +// JsonStringToBinary(). It will use the DescriptorPool of the passed-in +// message to resolve Any types. +// +// Please note that non-OK statuses are not a stable output of this API and +// subject to change without notice. +PROTOBUF_EXPORT absl::Status JsonStringToMessage(absl::string_view input, + Message* message, + const ParseOptions& options); + +inline absl::Status JsonStringToMessage(absl::string_view input, + Message* message) { + return JsonStringToMessage(input, message, ParseOptions()); +} + +// Converts protobuf binary data to JSON. +// The conversion will fail if: +// 1. TypeResolver fails to resolve a type. +// 2. input is not valid protobuf wire format, or conflicts with the type +// information returned by TypeResolver. +// Note that unknown fields will be discarded silently. +// +// Please note that non-OK statuses are not a stable output of this API and +// subject to change without notice. +PROTOBUF_EXPORT absl::Status BinaryToJsonStream( + google::protobuf::util::TypeResolver* resolver, const std::string& type_url, + io::ZeroCopyInputStream* binary_input, + io::ZeroCopyOutputStream* json_output, const PrintOptions& options); + +inline absl::Status BinaryToJsonStream(google::protobuf::util::TypeResolver* resolver, + const std::string& type_url, + io::ZeroCopyInputStream* binary_input, + io::ZeroCopyOutputStream* json_output) { + return BinaryToJsonStream(resolver, type_url, binary_input, json_output, + PrintOptions()); +} + +PROTOBUF_EXPORT absl::Status BinaryToJsonString( + google::protobuf::util::TypeResolver* resolver, const std::string& type_url, + const std::string& binary_input, std::string* json_output, + const PrintOptions& options); + +inline absl::Status BinaryToJsonString(google::protobuf::util::TypeResolver* resolver, + const std::string& type_url, + const std::string& binary_input, + std::string* json_output) { + return BinaryToJsonString(resolver, type_url, binary_input, json_output, + PrintOptions()); +} + +// Converts JSON data to protobuf binary format. +// The conversion will fail if: +// 1. TypeResolver fails to resolve a type. +// 2. input is not valid JSON format, or conflicts with the type +// information returned by TypeResolver. +// +// Please note that non-OK statuses are not a stable output of this API and +// subject to change without notice. +PROTOBUF_EXPORT absl::Status JsonToBinaryStream( + google::protobuf::util::TypeResolver* resolver, const std::string& type_url, + io::ZeroCopyInputStream* json_input, + io::ZeroCopyOutputStream* binary_output, const ParseOptions& options); + +inline absl::Status JsonToBinaryStream( + google::protobuf::util::TypeResolver* resolver, const std::string& type_url, + io::ZeroCopyInputStream* json_input, + io::ZeroCopyOutputStream* binary_output) { + return JsonToBinaryStream(resolver, type_url, json_input, binary_output, + ParseOptions()); +} + +PROTOBUF_EXPORT absl::Status JsonToBinaryString( + google::protobuf::util::TypeResolver* resolver, const std::string& type_url, + absl::string_view json_input, std::string* binary_output, + const ParseOptions& options); + +inline absl::Status JsonToBinaryString(google::protobuf::util::TypeResolver* resolver, + const std::string& type_url, + absl::string_view json_input, + std::string* binary_output) { + return JsonToBinaryString(resolver, type_url, json_input, binary_output, + ParseOptions()); +} +} // namespace json +} // namespace protobuf +} // namespace google + +#include "google/protobuf/port_undef.inc" + +#endif // GOOGLE_PROTOBUF_JSON_JSON_H__ diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/json/json_test.cc similarity index 93% rename from src/google/protobuf/util/json_util_test.cc rename to src/google/protobuf/json/json_test.cc index 3b582c48c5..1abf851951 100644 --- a/src/google/protobuf/util/json_util_test.cc +++ b/src/google/protobuf/json/json_test.cc @@ -28,7 +28,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "google/protobuf/util/json_util.h" +#include "google/protobuf/json/json.h" #include #include @@ -47,16 +47,12 @@ #include #include "absl/status/status.h" #include "absl/status/statusor.h" -#include "absl/strings/escaping.h" #include "absl/strings/string_view.h" #include "google/protobuf/descriptor_database.h" #include "google/protobuf/dynamic_message.h" #include "google/protobuf/io/zero_copy_stream.h" #include "google/protobuf/io/zero_copy_stream_impl_lite.h" -#include "google/protobuf/util/internal/testdata/maps.pb.h" #include "google/protobuf/util/json_format.pb.h" -#include "google/protobuf/util/json_format.pb.h" -#include "google/protobuf/util/json_format_proto3.pb.h" #include "google/protobuf/util/json_format_proto3.pb.h" #include "google/protobuf/util/type_resolver.h" #include "google/protobuf/util/type_resolver_util.h" @@ -65,26 +61,21 @@ // Must be included last. #include "google/protobuf/port_def.inc" -bool IsJson2() { - // Pay no attention to the person behind the curtain. - return false; -} - namespace google { namespace protobuf { -namespace util { +namespace json { namespace { +using ::google::protobuf::util::TypeResolver; +using ::proto3::MapIn; using ::proto3::TestAny; using ::proto3::TestEnumValue; using ::proto3::TestMap; using ::proto3::TestMessage; using ::proto3::TestOneof; using ::proto3::TestWrapper; -using ::proto_util_converter::testing::MapIn; using ::testing::ElementsAre; using ::testing::IsEmpty; using ::testing::Not; -using ::testing::Pair; using ::testing::SizeIs; // TODO(b/234474291): Use the gtest versions once that's available in OSS. @@ -119,7 +110,7 @@ enum class Codec { class JsonTest : public testing::TestWithParam { protected: absl::StatusOr ToJson(const Message& proto, - JsonPrintOptions options = {}) { + PrintOptions options = {}) { if (GetParam() == Codec::kReflective) { std::string result; RETURN_IF_ERROR(MessageToJsonString(proto, &result, options)); @@ -141,7 +132,7 @@ class JsonTest : public testing::TestWithParam { // The out parameter comes first since `json` tends to be a very long string, // and clang-format does a poor job if it is not the last parameter. absl::Status ToProto(Message& proto, absl::string_view json, - JsonParseOptions options = {}) { + ParseOptions options = {}) { if (GetParam() == Codec::kReflective) { return JsonStringToMessage(json, &proto, options); } @@ -163,14 +154,15 @@ class JsonTest : public testing::TestWithParam { template absl::StatusOr ToProto(absl::string_view json, - JsonParseOptions options = {}) { + ParseOptions options = {}) { Proto proto; RETURN_IF_ERROR(ToProto(proto, json, options)); return proto; } - std::unique_ptr resolver_{NewTypeResolverForDescriptorPool( - "type.googleapis.com", DescriptorPool::generated_pool())}; + std::unique_ptr resolver_{ + google::protobuf::util::NewTypeResolverForDescriptorPool( + "type.googleapis.com", DescriptorPool::generated_pool())}; }; INSTANTIATE_TEST_SUITE_P(JsonTestSuite, JsonTest, @@ -188,7 +180,7 @@ TEST_P(JsonTest, TestWhitespaces) { IsOkAndHolds( R"({"stringValue":"foo","messageValue":{},"repeatedBoolValue":[true,false]})")); - JsonPrintOptions options; + PrintOptions options; options.add_whitespace = true; // Note: whitespace here is significant. EXPECT_THAT(ToJson(m, options), IsOkAndHolds(R"({ @@ -206,7 +198,7 @@ TEST_P(JsonTest, TestDefaultValues) { TestMessage m; EXPECT_THAT(ToJson(m), IsOkAndHolds("{}")); - JsonPrintOptions options; + PrintOptions options; options.always_print_primitive_fields = true; EXPECT_THAT(ToJson(m, options), IsOkAndHolds("{\"boolValue\":false," "\"int32Value\":0," @@ -281,9 +273,6 @@ TEST_P(JsonTest, TestDefaultValues) { R"("defaultForeignEnum":"FOREIGN_BAR","defaultImportEnum":"IMPORT_BAR",)" R"("defaultStringPiece":"abc","defaultCord":"123"})")); - // The ESF parser actually gets this wrong, and serializes floats whose - // default value is non-finite as 0. We make sure to reproduce this bug. - if (IsJson2()) { EXPECT_THAT( ToJson(protobuf_unittest::TestExtremeDefaultValues(), options), IsOkAndHolds( @@ -298,29 +287,13 @@ TEST_P(JsonTest, TestDefaultValues) { R"(,"reallySmallInt64":"-9223372036854775808","stringWithZero":"hel\u0000lo")" R"(,"bytesWithZero":"d29yXDAwMGxk","stringPieceWithZero":"ab\u0000c")" R"(,"cordWithZero":"12\u00003","replacementString":"${unknown}"})")); - } else { - EXPECT_THAT( - ToJson(protobuf_unittest::TestExtremeDefaultValues(), options), - IsOkAndHolds( - R"({"escapedBytes":"XDAwMFwwMDFcMDA3XDAxMFwwMTRcblxyXHRcMDEzXFxcJ1wiXDM3Ng==")" - R"(,"largeUint32":4294967295,"largeUint64":"18446744073709551615",)" - R"("smallInt32":-2147483647,"smallInt64":"-9223372036854775807")" - R"(,"reallySmallInt32":-2147483648,"reallySmallInt64":"-9223372036854775808",)" - R"("utf8String":"ሴ","zeroFloat":0,"oneFloat":1,"smallFloat":1.5,)" - R"("negativeOneFloat":-1,"negativeFloat":-1.5,"largeFloat":2e+08,)" - R"("smallNegativeFloat":-8e-28,"infDouble":0,"negInfDouble":0)" - R"(,"nanDouble":0,"infFloat":0,"negInfFloat":0,"nanFloat":0)" - R"(,"cppTrigraph":"? ? ?? ?? ??? ??/ ??-","stringWithZero":"hel\u0000lo")" - R"(,"bytesWithZero":"d29yXDAwMGxk","stringPieceWithZero":"ab\u0000c")" - R"(,"cordWithZero":"12\u00003","replacementString":"${unknown}"})")); - } } TEST_P(JsonTest, TestPreserveProtoFieldNames) { TestMessage m; m.mutable_message_value(); - JsonPrintOptions options; + PrintOptions options; options.preserve_proto_field_names = true; EXPECT_THAT(ToJson(m, options), IsOkAndHolds("{\"message_value\":{}}")); @@ -348,7 +321,7 @@ TEST_P(JsonTest, TestAlwaysPrintEnumsAsInts) { orig.add_repeated_enum_value(proto3::FOO); orig.add_repeated_enum_value(proto3::BAR); - JsonPrintOptions print_options; + PrintOptions print_options; print_options.always_print_enums_as_ints = true; auto printed = ToJson(orig, print_options); @@ -369,7 +342,7 @@ TEST_P(JsonTest, TestPrintEnumsAsIntsWithDefaultValue) { orig.set_enum_value2(proto3::FOO); orig.set_enum_value3(proto3::BAR); - JsonPrintOptions print_options; + PrintOptions print_options; print_options.always_print_enums_as_ints = true; print_options.always_print_primitive_fields = true; @@ -388,7 +361,7 @@ TEST_P(JsonTest, TestPrintEnumsAsIntsWithDefaultValue) { TEST_P(JsonTest, TestPrintProto2EnumAsIntWithDefaultValue) { protobuf_unittest::TestDefaultEnumValue orig; - JsonPrintOptions print_options; + PrintOptions print_options; print_options.always_print_enums_as_ints = true; print_options.always_print_primitive_fields = true; @@ -575,12 +548,13 @@ TEST_P(JsonTest, RepeatedMapKey) { "twiceKey": 0, "twiceKey": 1 } - })json"), StatusIs(absl::StatusCode::kInvalidArgument)); + })json"), + StatusIs(absl::StatusCode::kInvalidArgument)); } TEST_P(JsonTest, ParsePrimitiveMapIn) { MapIn message; - JsonPrintOptions print_options; + PrintOptions print_options; print_options.always_print_primitive_fields = true; auto printed = ToJson(message, print_options); ASSERT_THAT( @@ -594,7 +568,7 @@ TEST_P(JsonTest, ParsePrimitiveMapIn) { TEST_P(JsonTest, PrintPrimitiveOneof) { TestOneof message; - JsonPrintOptions options; + PrintOptions options; options.always_print_primitive_fields = true; message.mutable_oneof_message_value(); EXPECT_THAT(ToJson(message, options), @@ -641,7 +615,7 @@ TEST_P(JsonTest, RepeatedOneofKeys) { } TEST_P(JsonTest, TestParseIgnoreUnknownFields) { - JsonParseOptions options; + ParseOptions options; options.ignore_unknown_fields = true; EXPECT_OK(ToProto(R"({"unknownName":0})", options)); @@ -913,7 +887,7 @@ TEST_P(JsonTest, TestParsingUnknownAnyFields) { EXPECT_THAT(ToProto(input), StatusIs(absl::StatusCode::kInvalidArgument)); - JsonParseOptions options; + ParseOptions options; options.ignore_unknown_fields = true; auto m = ToProto(input, options); ASSERT_OK(m); @@ -937,7 +911,7 @@ TEST_P(JsonTest, TestParsingUnknownEnumsProto2) { EXPECT_THAT(ToProto(input), StatusIs(absl::StatusCode::kInvalidArgument)); - JsonParseOptions options; + ParseOptions options; options.ignore_unknown_fields = true; auto m = ToProto(input, options); ASSERT_OK(m); @@ -952,7 +926,7 @@ TEST_P(JsonTest, TestParsingUnknownEnumsProto3) { ASSERT_THAT(ToProto(m, input), StatusIs(absl::StatusCode::kInvalidArgument)); EXPECT_EQ(m.enum_value(), proto3::BAR); // Keep previous value - JsonParseOptions options; + ParseOptions options; options.ignore_unknown_fields = true; ASSERT_OK(ToProto(m, input, options)); EXPECT_EQ(m.enum_value(), 0); // Unknown enum value must be decoded as 0 @@ -966,7 +940,7 @@ TEST_P(JsonTest, TestParsingUnknownEnumsProto3FromInt) { ASSERT_OK(ToProto(m, input)); EXPECT_EQ(m.enum_value(), 12345); - JsonParseOptions options; + ParseOptions options; options.ignore_unknown_fields = true; ASSERT_OK(ToProto(m, input, options)); EXPECT_EQ(m.enum_value(), 12345); @@ -980,7 +954,7 @@ TEST_P(JsonTest, TestParsingUnknownEnumsProto3FromObject) { EXPECT_THAT(ToProto(input), StatusIs(absl::StatusCode::kInvalidArgument)); - JsonParseOptions options; + ParseOptions options; options.ignore_unknown_fields = true; EXPECT_THAT(ToProto(input, options), StatusIs(absl::StatusCode::kInvalidArgument)); @@ -992,7 +966,7 @@ TEST_P(JsonTest, TestParsingUnknownEnumsProto3FromArray) { EXPECT_THAT(ToProto(input), StatusIs(absl::StatusCode::kInvalidArgument)); - JsonParseOptions options; + ParseOptions options; options.ignore_unknown_fields = true; EXPECT_THAT(ToProto(input, options), StatusIs(absl::StatusCode::kInvalidArgument)); @@ -1008,7 +982,7 @@ TEST_P(JsonTest, TestParsingEnumCaseSensitive) { } TEST_P(JsonTest, TestParsingEnumLowercase) { - JsonParseOptions options; + ParseOptions options; options.case_insensitive_enum_parsing = true; auto m = ToProto(R"json({"enum_value": "TLSv1_2"})json", options); @@ -1020,16 +994,14 @@ TEST_P(JsonTest, TestParsingEnumIgnoreCase) { TestMessage m; m.set_enum_value(proto3::FOO); - JsonParseOptions options; + ParseOptions options; options.case_insensitive_enum_parsing = true; ASSERT_OK(ToProto(m, R"json({"enum_value":"bar"})json", options)); EXPECT_EQ(m.enum_value(), proto3::BAR); } -// This functionality is not correctly implemented by the ESF parser, so -// the test is only turned on when testing json2. TEST_P(JsonTest, Extensions) { - if (GetParam() == Codec::kResolver || !IsJson2()) { + if (GetParam() == Codec::kResolver) { GTEST_SKIP(); } @@ -1289,7 +1261,7 @@ TEST_P(JsonTest, HtmlEscape) { IsOkAndHolds(R"({"stringValue":"\u003c/script\u003e"})")); proto3::TestEvilJson m2; - JsonPrintOptions opts; + PrintOptions opts; opts.always_print_primitive_fields = true; EXPECT_THAT( ToJson(m2, opts), @@ -1306,15 +1278,9 @@ TEST_P(JsonTest, FieldOrder) { resolver_.get(), "type.googleapis.com/proto3.TestMessage", "\x18\x03\xb0\x01\x02\x08\x01\xb0\x01\x02", &out); ASSERT_OK(s); - if (IsJson2()) { EXPECT_EQ( out, R"({"boolValue":true,"int64Value":"3","repeatedInt32Value":[2,2]})"); - } else { - EXPECT_EQ( - out, - R"({"int64Value":"3","repeatedInt32Value":[2],"boolValue":true,"repeatedInt32Value":[2]})"); - } } // JSON values get special treatment when it comes to pre-existing values in @@ -1332,6 +1298,6 @@ TEST_P(JsonTest, ClearPreExistingRepeatedInJsonValues) { } } // namespace -} // namespace util +} // namespace json } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h index fd03c6b9b9..b831fa6ab5 100644 --- a/src/google/protobuf/message.h +++ b/src/google/protobuf/message.h @@ -914,8 +914,7 @@ class PROTOBUF_EXPORT Reflection final { // Try to find an extension of this message type by fully-qualified field // name. Returns nullptr if no extension is known for this name or number. - const FieldDescriptor* FindKnownExtensionByName( - const std::string& name) const; + const FieldDescriptor* FindKnownExtensionByName(absl::string_view name) const; // Try to find an extension of this message type by field number. // Returns nullptr if no extension is known for this name or number. diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc index defc8158b9..eea99e0e2c 100644 --- a/src/google/protobuf/message_lite.cc +++ b/src/google/protobuf/message_lite.cc @@ -48,6 +48,7 @@ #include "google/protobuf/io/zero_copy_stream_impl_lite.h" #include "google/protobuf/arena.h" #include "absl/base/dynamic_annotations.h" +#include "absl/strings/cord.h" #include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" diff --git a/src/google/protobuf/message_unittest.inc b/src/google/protobuf/message_unittest.inc index 1217c403ea..742f3bd5b6 100644 --- a/src/google/protobuf/message_unittest.inc +++ b/src/google/protobuf/message_unittest.inc @@ -45,6 +45,7 @@ #include #include "google/protobuf/message.h" +#include "absl/strings/cord.h" #ifndef _MSC_VER #include #endif @@ -1430,5 +1431,49 @@ TEST(MESSAGE_TEST_NAME, TestRepeatedStringParsers) { } } +TEST(MESSAGE_TEST_NAME, TestRegressionOnParseFailureNotSettingHasBits) { + std::string single_field; + // We use blocks because we want fully new instances of the proto. We are + // testing .Clear(), so we can't use it to set up the test. + { + UNITTEST::TestAllTypes message; + message.set_optional_int32(17); + single_field = message.SerializeAsString(); + } + const auto validate_message = [] (auto& message) { + if (!message.has_optional_int32()) { + EXPECT_EQ(message.optional_int32(), 0); + } + message.Clear(); + EXPECT_FALSE(message.has_optional_int32()); + EXPECT_EQ(message.optional_int32(), 0); + }; + { + // Verify the setup is correct. + UNITTEST::TestAllTypes message; + EXPECT_FALSE(message.has_optional_int32()); + EXPECT_EQ(message.optional_int32(), 0); + EXPECT_TRUE(message.ParseFromString(single_field)); + validate_message(message); + } + { + // Run the regression. + // These are the steps: + // - The stream contains a fast field, and then a failure in MiniParse + // - The parsing fails. + // - We call clear. + // - The fast field should be reset. + UNITTEST::TestAllTypes message; + EXPECT_FALSE(message.has_optional_int32()); + EXPECT_EQ(message.optional_int32(), 0); + // The second tag will fail to parse because it has too many continuation + // bits. + auto with_error = + absl::StrCat(single_field, std::string(100, static_cast(0x80))); + EXPECT_FALSE(message.ParseFromString(with_error)); + validate_message(message); + } +} + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/parse_context.cc b/src/google/protobuf/parse_context.cc index 34063195c8..63f76fd012 100644 --- a/src/google/protobuf/parse_context.cc +++ b/src/google/protobuf/parse_context.cc @@ -382,7 +382,7 @@ void PrintUTF8ErrorLog(absl::string_view message_name, bool emit_stacktrace); bool VerifyUTF8(absl::string_view str, const char* field_name) { - if (!IsStructurallyValidUTF8(str)) { + if (!::google::protobuf::internal::IsStructurallyValidUTF8(str)) { PrintUTF8ErrorLog("", field_name, "parsing", false); return false; } diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc index 0fcc90d815..021ac4f587 100644 --- a/src/google/protobuf/port_def.inc +++ b/src/google/protobuf/port_def.inc @@ -221,7 +221,7 @@ #ifdef PROTOBUF_VERSION #error PROTOBUF_VERSION was previously defined #endif -#define PROTOBUF_VERSION 3021006 +#define PROTOBUF_VERSION 3021007 #ifdef PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC #error PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC was previously defined @@ -822,15 +822,11 @@ # endif #endif -// Tail call table-driven parsing can be enabled by defining -// PROTOBUF_EXPERIMENTAL_USE_TAIL_CALL_TABLE_PARSER at compilation time. -// We hope to turn on table-driven parsing by default in Q4 2022. +// Tail call table-driven parsing is enabled by default. #ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED #error PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED was previously declared #endif -#if defined(PROTOBUF_EXPERIMENTAL_USE_TAIL_CALL_TABLE_PARSER) #define PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED 1 -#endif #ifdef PROTOBUF_USE_TABLE_PARSER_ON_REFLECTION #error PROTOBUF_USE_TABLE_PARSER_ON_REFLECTION was previously defined @@ -978,13 +974,29 @@ #undef DEBUG #endif // defined(__clang__) || PROTOBUF_GNUC_MIN(3, 0) || defined(_MSC_VER) -#if PROTOBUF_GNUC_MIN(3, 0) +// Protobuf does not support building with a number of warnings that are noisy +// (and of variable quality across compiler versions) or impossible to implement +// effectively but which people turn on anyways. +#ifdef __GNUC__ +#pragma GCC diagnostic push +// Some of the warnings below only exist in some GCC versions; those version +// ranges are poorly documented. +#pragma GCC diagnostic ignored "-Wpragmas" // GCC does not allow disabling diagnostics within an expression: // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60875, so we disable this one // globally even though it's only used for PROTOBUF_FIELD_OFFSET. -#pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Winvalid-offsetof" -#endif +// This warning verifies that non-void-returning functions return a value in +// all paths. However, this warning is noisy, and requires adding unnecessary +// returns in unreachable positions. +#pragma GCC diagnostic ignored "-Wreturn-type" +// Some versions of GCC seem to think that +// [this] { Foo(); } +// leaves `this` unused, even though `Foo();` is a member function of the +// captured `this`. +// https://bugzilla.mozilla.org/show_bug.cgi?id=1373625 +#pragma GCC diagnostic ignored "-Wunused-lambda-capture" +#endif // __GNUC__ // Silence some MSVC warnings in all our code. #ifdef _MSC_VER diff --git a/src/google/protobuf/reflection_internal.h b/src/google/protobuf/reflection_internal.h index 3fdee895e0..5e2cfa07eb 100644 --- a/src/google/protobuf/reflection_internal.h +++ b/src/google/protobuf/reflection_internal.h @@ -31,6 +31,7 @@ #ifndef GOOGLE_PROTOBUF_REFLECTION_INTERNAL_H__ #define GOOGLE_PROTOBUF_REFLECTION_INTERNAL_H__ +#include "absl/strings/cord.h" #include "google/protobuf/map_field.h" #include "google/protobuf/reflection.h" #include "google/protobuf/repeated_field.h" diff --git a/src/google/protobuf/repeated_field.cc b/src/google/protobuf/repeated_field.cc index f8212e3632..9e1d41957f 100644 --- a/src/google/protobuf/repeated_field.cc +++ b/src/google/protobuf/repeated_field.cc @@ -38,6 +38,7 @@ #include "google/protobuf/stubs/logging.h" #include "google/protobuf/stubs/common.h" +#include "absl/strings/cord.h" // Must be included last. #include "google/protobuf/port_def.inc" diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h index ccae6bb97a..bc70129181 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h @@ -716,7 +716,7 @@ inline void RepeatedField::Add(Iter begin, Iter end) { if (std::is_base_of< std::forward_iterator_tag, typename std::iterator_traits::iterator_category>::value) { - int additional = std::distance(begin, end); + int additional = static_cast(std::distance(begin, end)); if (additional == 0) return; int new_size = current_size_ + additional; diff --git a/src/google/protobuf/repeated_field_reflection_unittest.cc b/src/google/protobuf/repeated_field_reflection_unittest.cc index ccecdd0494..2d30578741 100644 --- a/src/google/protobuf/repeated_field_reflection_unittest.cc +++ b/src/google/protobuf/repeated_field_reflection_unittest.cc @@ -38,6 +38,7 @@ #include "google/protobuf/reflection.h" #include #include "absl/base/casts.h" +#include "absl/strings/cord.h" #include "google/protobuf/port.h" #include "google/protobuf/test_util.h" diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc index 3baf6f25bb..eeecf078b0 100644 --- a/src/google/protobuf/repeated_field_unittest.cc +++ b/src/google/protobuf/repeated_field_unittest.cc @@ -50,11 +50,12 @@ #include "google/protobuf/stubs/logging.h" #include "google/protobuf/stubs/common.h" #include "google/protobuf/unittest.pb.h" -#include "google/protobuf/stubs/strutil.h" #include #include #include "absl/numeric/bits.h" +#include "absl/strings/cord.h" #include "absl/strings/str_cat.h" +#include "google/protobuf/stubs/strutil.h" #include "google/protobuf/stubs/stl_util.h" // Must be included last. diff --git a/src/google/protobuf/repeated_ptr_field.h b/src/google/protobuf/repeated_ptr_field.h index f58481dff3..706a005761 100644 --- a/src/google/protobuf/repeated_ptr_field.h +++ b/src/google/protobuf/repeated_ptr_field.h @@ -1351,7 +1351,7 @@ inline void RepeatedPtrField::Add(Iter begin, Iter end) { if (std::is_base_of< std::forward_iterator_tag, typename std::iterator_traits::iterator_category>::value) { - int reserve = std::distance(begin, end); + int reserve = static_cast(std::distance(begin, end)); Reserve(size() + reserve); } for (; begin != end; ++begin) { @@ -1496,8 +1496,8 @@ RepeatedPtrField::erase(const_iterator position) { template inline typename RepeatedPtrField::iterator RepeatedPtrField::erase(const_iterator first, const_iterator last) { - size_type pos_offset = std::distance(cbegin(), first); - size_type last_offset = std::distance(cbegin(), last); + size_type pos_offset = static_cast(std::distance(cbegin(), first)); + size_type last_offset = static_cast(std::distance(cbegin(), last)); DeleteSubrange(pos_offset, last_offset - pos_offset); return begin() + pos_offset; } diff --git a/src/google/protobuf/source_context.pb.h b/src/google/protobuf/source_context.pb.h index 8efcd328ef..8f1aeffb5e 100644 --- a/src/google/protobuf/source_context.pb.h +++ b/src/google/protobuf/source_context.pb.h @@ -15,7 +15,7 @@ #error "your headers." #endif // PROTOBUF_VERSION -#if 3021006 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021007 < PROTOBUF_MIN_PROTOC_VERSION #error "This file was generated by an older version of protoc which is" #error "incompatible with your Protocol Buffer headers. Please" #error "regenerate this file with a newer version of protoc." diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h index 1292783621..36ae0b86c6 100644 --- a/src/google/protobuf/struct.pb.h +++ b/src/google/protobuf/struct.pb.h @@ -15,7 +15,7 @@ #error "your headers." #endif // PROTOBUF_VERSION -#if 3021006 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021007 < PROTOBUF_MIN_PROTOC_VERSION #error "This file was generated by an older version of protoc which is" #error "incompatible with your Protocol Buffer headers. Please" #error "regenerate this file with a newer version of protoc." diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h index bdc03b06a3..cbcee3c926 100644 --- a/src/google/protobuf/stubs/common.h +++ b/src/google/protobuf/stubs/common.h @@ -81,7 +81,7 @@ namespace internal { // The current version, represented as a single integer to make comparison // easier: major * 10^6 + minor * 10^3 + micro -#define GOOGLE_PROTOBUF_VERSION 3021006 +#define GOOGLE_PROTOBUF_VERSION 3021007 // A suffix string for alpha, beta or rc releases. Empty for stable releases. #define GOOGLE_PROTOBUF_VERSION_SUFFIX "" diff --git a/src/google/protobuf/stubs/platform_macros.h b/src/google/protobuf/stubs/platform_macros.h index 24799600dc..d10faf9aa2 100644 --- a/src/google/protobuf/stubs/platform_macros.h +++ b/src/google/protobuf/stubs/platform_macros.h @@ -122,11 +122,11 @@ GOOGLE_PROTOBUF_PLATFORM_ERROR #undef GOOGLE_PROTOBUF_PLATFORM_ERROR -#if defined(GOOGLE_PROTOBUF_OS_ANDROID) || defined(GOOGLE_PROTOBUF_OS_IPHONE) || defined(__OpenBSD__) +#if defined(GOOGLE_PROTOBUF_OS_ANDROID) || defined(GOOGLE_PROTOBUF_OS_IPHONE) // Android ndk does not support the __thread keyword very well yet. Here // we use pthread_key_create()/pthread_getspecific()/... methods for // TLS support on android. -// iOS and OpenBSD also do not support the __thread keyword. +// iOS also does not support the __thread keyword. #define GOOGLE_PROTOBUF_NO_THREADLOCAL #endif diff --git a/src/google/protobuf/test_messages_proto2.proto b/src/google/protobuf/test_messages_proto2.proto index b04d8bb475..1cc7c86ae2 100644 --- a/src/google/protobuf/test_messages_proto2.proto +++ b/src/google/protobuf/test_messages_proto2.proto @@ -40,6 +40,7 @@ syntax = "proto2"; package protobuf_test_messages.proto2; option java_package = "com.google.protobuf_test_messages.proto2"; +option objc_class_prefix = "Proto2"; // This is the default, but we specify it here explicitly. option optimize_for = SPEED; @@ -195,21 +196,21 @@ message TestAllTypesProto2 { } // default values - optional int32 default_int32 = 241 [ default = -123456789]; - optional int64 default_int64 = 242 [ default = -9123456789123456789]; - optional uint32 default_uint32 = 243 [ default = 2123456789]; - optional uint64 default_uint64 = 244 [ default = 10123456789123456789]; - optional sint32 default_sint32 = 245 [ default = -123456789]; + optional int32 default_int32 = 241 [default = -123456789]; + optional int64 default_int64 = 242 [default = -9123456789123456789]; + optional uint32 default_uint32 = 243 [default = 2123456789]; + optional uint64 default_uint64 = 244 [default = 10123456789123456789]; + optional sint32 default_sint32 = 245 [default = -123456789]; optional sint64 default_sint64 = 246 [default = -9123456789123456789]; - optional fixed32 default_fixed32 = 247 [ default = 2123456789]; - optional fixed64 default_fixed64 = 248 [ default = 10123456789123456789]; - optional sfixed32 default_sfixed32 = 249 [ default = -123456789]; + optional fixed32 default_fixed32 = 247 [default = 2123456789]; + optional fixed64 default_fixed64 = 248 [default = 10123456789123456789]; + optional sfixed32 default_sfixed32 = 249 [default = -123456789]; optional sfixed64 default_sfixed64 = 250 [default = -9123456789123456789]; - optional float default_float = 251 [ default = 9e9]; - optional double default_double = 252 [ default = 7e22]; - optional bool default_bool = 253 [ default = true]; - optional string default_string = 254 [ default = "Rosebud"]; - optional bytes default_bytes = 255 [ default = "joshua"]; + optional float default_float = 251 [default = 9e9]; + optional double default_double = 252 [default = 7e22]; + optional bool default_bool = 253 [default = true]; + optional string default_string = 254 [default = "Rosebud"]; + optional bytes default_bytes = 255 [default = "joshua"]; // Test field-name-to-JSON-name convention. // (protobuf says names can be any valid C/C++ identifier.) @@ -282,8 +283,7 @@ message UnknownToTestAllTypes { repeated int32 repeated_int32 = 1011; } -message NullHypothesisProto2 { -} +message NullHypothesisProto2 {} message EnumOnlyProto2 { enum Bool { diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc index cf2afa2ffb..560d4131e7 100644 --- a/src/google/protobuf/text_format.cc +++ b/src/google/protobuf/text_format.cc @@ -93,6 +93,12 @@ namespace internal { const char kDebugStringSilentMarker[] = ""; const char kDebugStringSilentMarkerForDetection[] = "\t "; +// Controls insertion of a marker making debug strings non-parseable. +PROTOBUF_EXPORT std::atomic enable_debug_text_redaction_marker; + +// Controls insertion of a randomized marker in debug strings. +PROTOBUF_EXPORT std::atomic enable_debug_text_random_marker; + // Controls insertion of kDebugStringSilentMarker. PROTOBUF_EXPORT std::atomic enable_debug_text_format_marker; } // namespace internal @@ -104,6 +110,12 @@ std::string Message::DebugString() const { printer.SetExpandAny(true); printer.SetInsertSilentMarker(internal::enable_debug_text_format_marker.load( std::memory_order_relaxed)); + printer.SetRedactDebugString( + internal::enable_debug_text_redaction_marker.load( + std::memory_order_relaxed)); + printer.SetRandomizeDebugString( + internal::enable_debug_text_random_marker.load( + std::memory_order_relaxed)); printer.PrintToString(*this, &debug_string); @@ -118,6 +130,12 @@ std::string Message::ShortDebugString() const { printer.SetExpandAny(true); printer.SetInsertSilentMarker(internal::enable_debug_text_format_marker.load( std::memory_order_relaxed)); + printer.SetRedactDebugString( + internal::enable_debug_text_redaction_marker.load( + std::memory_order_relaxed)); + printer.SetRandomizeDebugString( + internal::enable_debug_text_random_marker.load( + std::memory_order_relaxed)); printer.PrintToString(*this, &debug_string); // Single line mode currently might have an extra space at the end. @@ -136,6 +154,12 @@ std::string Message::Utf8DebugString() const { printer.SetExpandAny(true); printer.SetInsertSilentMarker(internal::enable_debug_text_format_marker.load( std::memory_order_relaxed)); + printer.SetRedactDebugString( + internal::enable_debug_text_redaction_marker.load( + std::memory_order_relaxed)); + printer.SetRandomizeDebugString( + internal::enable_debug_text_random_marker.load( + std::memory_order_relaxed)); printer.PrintToString(*this, &debug_string); @@ -494,7 +518,7 @@ class TextFormat::Parser::ParserImpl { TryConsumeWhitespace(); int32_t field_number; - if (allow_field_number_ && safe_strto32(field_name, &field_number)) { + if (allow_field_number_ && absl::SimpleAtoi(field_name, &field_number)) { if (descriptor->IsExtensionNumber(field_number)) { field = finder_ ? finder_->FindExtensionByNumber(descriptor, field_number) @@ -2005,6 +2029,8 @@ TextFormat::Printer::Printer() use_field_number_(false), use_short_repeated_primitives_(false), insert_silent_marker_(false), + redact_debug_string_(false), + randomize_debug_string_(false), hide_unknown_fields_(false), print_message_fields_in_index_order_(false), expand_any_(false), diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h index bfae7e6de8..7dc776e77d 100644 --- a/src/google/protobuf/text_format.h +++ b/src/google/protobuf/text_format.h @@ -39,6 +39,7 @@ #define GOOGLE_PROTOBUF_TEXT_FORMAT_H__ +#include #include #include #include @@ -65,6 +66,11 @@ namespace protobuf { namespace internal { PROTOBUF_EXPORT extern const char kDebugStringSilentMarker[1]; PROTOBUF_EXPORT extern const char kDebugStringSilentMarkerForDetection[3]; + +PROTOBUF_EXPORT extern std::atomic enable_debug_text_redaction_marker; +PROTOBUF_EXPORT extern std::atomic enable_debug_text_random_marker; +PROTOBUF_EXPORT extern std::atomic enable_debug_text_format_marker; + } // namespace internal namespace io { @@ -380,9 +386,18 @@ class PROTOBUF_EXPORT TextFormat { friend std::string Message::ShortDebugString() const; friend std::string Message::Utf8DebugString() const; - // Sets whether *DebugString should insert a silent marker. + // Sets whether silent markers will be inserted. void SetInsertSilentMarker(bool v) { insert_silent_marker_ = v; } + // Sets whether strings will be redacted and thus unparsable. + void SetRedactDebugString(bool redact) { redact_debug_string_ = redact; } + + // Sets whether the output string should be made non-deterministic. + // This discourages equality checks based on serialized string comparisons. + void SetRandomizeDebugString(bool randomize) { + randomize_debug_string_ = randomize; + } + // Forward declaration of an internal class used to print the text // output to the OutputStream (see text_format.cc for implementation). class TextGenerator; @@ -446,6 +461,8 @@ class PROTOBUF_EXPORT TextFormat { bool use_field_number_; bool use_short_repeated_primitives_; bool insert_silent_marker_; + bool redact_debug_string_; + bool randomize_debug_string_; bool hide_unknown_fields_; bool print_message_fields_in_index_order_; bool expand_any_; diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc index e11533da34..fa7cc63a45 100644 --- a/src/google/protobuf/text_format_unittest.cc +++ b/src/google/protobuf/text_format_unittest.cc @@ -54,7 +54,6 @@ #include "google/protobuf/unittest_proto3.pb.h" #include "google/protobuf/io/tokenizer.h" #include "google/protobuf/io/zero_copy_stream_impl.h" -#include "google/protobuf/stubs/strutil.h" #include #include "google/protobuf/testing/googletest.h" #include @@ -66,6 +65,7 @@ #include "google/protobuf/test_util.h" #include "google/protobuf/test_util2.h" +#include "google/protobuf/stubs/strutil.h" // Must be included last. #include "google/protobuf/port_def.inc" @@ -73,11 +73,6 @@ namespace google { namespace protobuf { -namespace internal { -// Controls insertion of DEBUG_STRING_SILENT_MARKER. -extern PROTOBUF_EXPORT std::atomic enable_debug_text_format_marker; -} // namespace internal - // Can't use an anonymous namespace here due to brokenness of Tru64 compiler. namespace text_format_unittest { diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h index 547b1e24f8..64f0d59d0e 100644 --- a/src/google/protobuf/timestamp.pb.h +++ b/src/google/protobuf/timestamp.pb.h @@ -15,7 +15,7 @@ #error "your headers." #endif // PROTOBUF_VERSION -#if 3021006 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021007 < PROTOBUF_MIN_PROTOC_VERSION #error "This file was generated by an older version of protoc which is" #error "incompatible with your Protocol Buffer headers. Please" #error "regenerate this file with a newer version of protoc." diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h index 66382466b7..18bf4cbfc3 100644 --- a/src/google/protobuf/type.pb.h +++ b/src/google/protobuf/type.pb.h @@ -15,7 +15,7 @@ #error "your headers." #endif // PROTOBUF_VERSION -#if 3021006 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021007 < PROTOBUF_MIN_PROTOC_VERSION #error "This file was generated by an older version of protoc which is" #error "incompatible with your Protocol Buffer headers. Please" #error "regenerate this file with a newer version of protoc." diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc index 3a6d8d70b3..7eecd300eb 100644 --- a/src/google/protobuf/unknown_field_set.cc +++ b/src/google/protobuf/unknown_field_set.cc @@ -40,6 +40,7 @@ #include "google/protobuf/io/zero_copy_stream.h" #include "google/protobuf/io/zero_copy_stream_impl.h" #include "google/protobuf/io/zero_copy_stream_impl_lite.h" +#include "absl/strings/cord.h" #include "absl/strings/internal/resize_uninitialized.h" #include "google/protobuf/extension_set.h" #include "google/protobuf/generated_message_tctable_decl.h" diff --git a/src/google/protobuf/unknown_field_set_unittest.cc b/src/google/protobuf/unknown_field_set_unittest.cc index 92fff73135..7093f3db88 100644 --- a/src/google/protobuf/unknown_field_set_unittest.cc +++ b/src/google/protobuf/unknown_field_set_unittest.cc @@ -54,6 +54,7 @@ #include #include "google/protobuf/testing/googletest.h" #include +#include "absl/strings/cord.h" #include "absl/synchronization/mutex.h" #include "absl/time/clock.h" #include "absl/time/time.h" diff --git a/src/google/protobuf/util/BUILD.bazel b/src/google/protobuf/util/BUILD.bazel index 6b1d3b2d4c..404b346044 100644 --- a/src/google/protobuf/util/BUILD.bazel +++ b/src/google/protobuf/util/BUILD.bazel @@ -118,45 +118,11 @@ cc_test( cc_library( name = "json_util", - srcs = ["json_util.cc"], hdrs = ["json_util.h"], copts = COPTS, strip_include_prefix = "/src", visibility = ["//:__subpackages__"], - deps = [ - ":type_resolver_util", - "//src/google/protobuf", - "//src/google/protobuf/io", - "//src/google/protobuf/io:zero_copy_sink", - "//src/google/protobuf/stubs", - "//src/google/protobuf/util/internal:default_value", - "//src/google/protobuf/util/internal:json", - "//src/google/protobuf/util/internal:protostream", - "//src/google/protobuf/util/internal:utility", - "@com_google_absl//absl/status", - ], -) - -cc_test( - name = "json_util_test", - srcs = ["json_util_test.cc"], - copts = COPTS, - data = [ - "//src/google/protobuf:testdata", - ], - deps = [ - ":json_format_cc_proto", - ":json_format_proto3_cc_proto", - ":json_util", - "//src/google/protobuf", - "//src/google/protobuf:cc_test_protos", - "//src/google/protobuf:test_util", - "//src/google/protobuf/testing", - "//src/google/protobuf/util/internal:maps_cc_proto", - "@com_google_absl//absl/status", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", - ], + deps = ["//src/google/protobuf/json"], ) cc_library( @@ -197,7 +163,6 @@ cc_library( "//src/google/protobuf", "//src/google/protobuf/io", "//src/google/protobuf/stubs", - "//src/google/protobuf/util/internal:utility", "@com_google_absl//absl/status", ], ) @@ -227,7 +192,6 @@ filegroup( "json_format.proto", "json_format_proto3.proto", "message_differencer_unittest.proto", - "//src/google/protobuf/util/internal:test_proto_srcs", ], visibility = [ "//pkg:__pkg__", @@ -240,11 +204,21 @@ proto_library( testonly = 1, srcs = ["json_format.proto"], strip_import_prefix = "/src", + deps = [ + "//:any_proto", + "//:duration_proto", + "//:field_mask_proto", + "//:struct_proto", + "//:test_protos", + "//:timestamp_proto", + "//:wrappers_proto", + ], ) cc_proto_library( name = "json_format_cc_proto", testonly = 1, + visibility = ["//:__subpackages__"], deps = [":json_format_proto"], ) @@ -267,6 +241,7 @@ proto_library( cc_proto_library( name = "json_format_proto3_cc_proto", testonly = 1, + visibility = ["//:__subpackages__"], deps = [":json_format_proto3_proto"], ) @@ -300,8 +275,6 @@ filegroup( srcs = glob([ "*_test.cc", "*unittest.cc", - ]) + [ - "//src/google/protobuf/util/internal:test_srcs", - ], + ]), visibility = ["//pkg:__pkg__"], ) diff --git a/src/google/protobuf/util/field_comparator.cc b/src/google/protobuf/util/field_comparator.cc index 9161d53072..bfab75a34e 100644 --- a/src/google/protobuf/util/field_comparator.cc +++ b/src/google/protobuf/util/field_comparator.cc @@ -129,7 +129,7 @@ FieldComparator::ComparisonResult SimpleFieldComparator::SimpleCompare( bool SimpleFieldComparator::CompareWithDifferencer( MessageDifferencer* differencer, const Message& message1, const Message& message2, const util::FieldContext* field_context) { - return differencer->Compare(message1, message2, + return differencer->Compare(message1, message2, false, field_context->parent_fields()); } diff --git a/src/google/protobuf/util/internal/BUILD.bazel b/src/google/protobuf/util/internal/BUILD.bazel deleted file mode 100644 index a982f165bb..0000000000 --- a/src/google/protobuf/util/internal/BUILD.bazel +++ /dev/null @@ -1,473 +0,0 @@ -################################################################################ -# Protocol Buffers C++ util internals. -################################################################################ - -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_proto_library", "cc_test") -load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix") -load("@rules_proto//proto:defs.bzl", "proto_library") -load("//build_defs:cpp_opts.bzl", "COPTS") - -package( - default_visibility = [ - "//pkg:__pkg__", - "//src/google/protobuf/util:__pkg__", - ], -) - -cc_library( - name = "constants", - hdrs = ["constants.h"], - strip_include_prefix = "/src", - deps = [ - "//src/google/protobuf/stubs", - ], -) - -cc_library( - name = "datapiece", - srcs = ["datapiece.cc"], - hdrs = ["datapiece.h"], - copts = COPTS, - strip_include_prefix = "/src", - deps = [ - ":constants", - ":utility", - "//src/google/protobuf", - "//src/google/protobuf/stubs", - "@com_google_absl//absl/strings", - ], -) - -cc_library( - name = "default_value", - srcs = ["default_value_objectwriter.cc"], - hdrs = ["default_value_objectwriter.h"], - copts = COPTS, - strip_include_prefix = "/src", - deps = [ - ":datapiece", - ":object_writer", - ":type_info", - ":utility", - "//src/google/protobuf/stubs", - ], -) - -cc_test( - name = "default_value_objectwriter_test", - srcs = ["default_value_objectwriter_test.cc"], - copts = COPTS, - deps = [ - ":default_value", - ":default_value_test_cc_proto", - ":expecting_objectwriter", - ":type_info_test_helper", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "expecting_objectwriter", - testonly = 1, - hdrs = ["expecting_objectwriter.h"], - strip_include_prefix = "/src", - deps = [":object_writer"], -) - -cc_library( - name = "field_mask_utility", - srcs = ["field_mask_utility.cc"], - hdrs = ["field_mask_utility.h"], - strip_include_prefix = "/src", - deps = [ - ":utility", - "//src/google/protobuf/stubs", - ], -) - -cc_library( - name = "json", - srcs = [ - "json_escaping.cc", - "json_objectwriter.cc", - "json_stream_parser.cc", - ], - hdrs = [ - "json_escaping.h", - "json_objectwriter.h", - "json_stream_parser.h", - ], - copts = COPTS, - strip_include_prefix = "/src", - deps = [ - ":object_writer", - ":utility", - "//src/google/protobuf", - "//src/google/protobuf/io", - "//src/google/protobuf/stubs", - "@com_google_absl//absl/status", - "@com_google_absl//absl/strings", - ], -) - -cc_test( - name = "json_objectwriter_test", - srcs = ["json_objectwriter_test.cc"], - copts = COPTS, - deps = [ - ":json", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "json_stream_parser_test", - srcs = ["json_stream_parser_test.cc"], - copts = COPTS, - deps = [ - ":expecting_objectwriter", - ":json", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "mock_error_listener", - testonly = 1, - hdrs = ["mock_error_listener.h"], - strip_include_prefix = "/src", - deps = [":protostream"], -) - -cc_library( - name = "object_writer", - srcs = ["object_writer.cc"], - hdrs = [ - "object_source.h", - "object_writer.h", - "structured_objectwriter.h", - ], - strip_include_prefix = "/src", - deps = [ - ":datapiece", - "//src/google/protobuf/stubs", - ], -) - -cc_library( - name = "type_info", - srcs = ["type_info.cc"], - hdrs = ["type_info.h"], - strip_include_prefix = "/src", - deps = [ - ":utility", - "//src/google/protobuf/stubs", - "//src/google/protobuf/util:type_resolver_util", - ], -) - -cc_library( - name = "type_info_test_helper", - testonly = 1, - srcs = ["type_info_test_helper.cc"], - hdrs = ["type_info_test_helper.h"], - copts = COPTS, - strip_include_prefix = "/src", - deps = [ - ":default_value", - ":protostream", - ":type_info", - ], -) - -cc_library( - name = "protostream", - srcs = [ - "error_listener.cc", - "proto_writer.cc", - "protostream_objectsource.cc", - "protostream_objectwriter.cc", - ], - hdrs = [ - "error_listener.h", - "location_tracker.h", - "object_location_tracker.h", - "proto_writer.h", - "protostream_objectsource.h", - "protostream_objectwriter.h", - ], - copts = COPTS, - strip_include_prefix = "/src", - deps = [ - ":constants", - ":datapiece", - ":field_mask_utility", - ":object_writer", - ":type_info", - ":utility", - "//src/google/protobuf", - "//src/google/protobuf/io", - "//src/google/protobuf/stubs", - "//src/google/protobuf/util:type_resolver_util", - "@com_google_absl//absl/strings", - ], -) - -cc_test( - name = "protostream_objectsource_test", - srcs = ["protostream_objectsource_test.cc"], - copts = COPTS, - deps = [ - ":anys_cc_proto", - ":books_cc_proto", - ":expecting_objectwriter", - ":field_mask_cc_proto", - ":maps_cc_proto", - ":oneofs_cc_proto", - ":proto3_cc_proto", - ":protostream", - ":struct_cc_proto", - ":timestamp_duration_cc_proto", - ":type_info_test_helper", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "protostream_objectwriter_test", - srcs = ["protostream_objectwriter_test.cc"], - copts = COPTS, - deps = [ - ":anys_cc_proto", - ":books_cc_proto", - ":field_mask_cc_proto", - ":maps_cc_proto", - ":mock_error_listener", - ":oneofs_cc_proto", - ":proto3_cc_proto", - ":protostream", - ":struct_cc_proto", - ":timestamp_duration_cc_proto", - ":type_info_test_helper", - ":wrappers_cc_proto", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "utility", - srcs = ["utility.cc"], - hdrs = ["utility.h"], - copts = COPTS, - strip_include_prefix = "/src", - deps = [ - ":constants", - "//src/google/protobuf", - "//src/google/protobuf/stubs", - "@com_google_absl//absl/strings", - ], -) - -# Testing protos: - -proto_library( - name = "anys_proto", - testonly = 1, - srcs = ["testdata/anys.proto"], - strip_import_prefix = "/src", - deps = [ - "//:any_proto", - "//:duration_proto", - "//:empty_proto", - "//:struct_proto", - "//:timestamp_proto", - "//:wrappers_proto", - ], -) - -cc_proto_library( - name = "anys_cc_proto", - testonly = 1, - visibility = ["//src/google/protobuf/util:__pkg__"], - deps = [":anys_proto"], -) - -proto_library( - name = "books_proto", - testonly = 1, - srcs = ["testdata/books.proto"], - strip_import_prefix = "/src", - deps = [":anys_proto"], -) - -cc_proto_library( - name = "books_cc_proto", - testonly = 1, - deps = [":books_proto"], -) - -proto_library( - name = "default_value_proto", - testonly = 1, - srcs = ["testdata/default_value.proto"], - strip_import_prefix = "/src", - deps = [ - "//:any_proto", - "//:struct_proto", - "//:wrappers_proto", - ], -) - -cc_proto_library( - name = "default_value_cc_proto", - testonly = 1, - deps = [":default_value_proto"], -) - -proto_library( - name = "default_value_test_proto", - testonly = 1, - srcs = ["testdata/default_value_test.proto"], - strip_import_prefix = "/src", -) - -cc_proto_library( - name = "default_value_test_cc_proto", - testonly = 1, - deps = [":default_value_test_proto"], -) - -proto_library( - name = "field_mask_proto", - testonly = 1, - srcs = ["testdata/field_mask.proto"], - strip_import_prefix = "/src", - deps = ["//:field_mask_proto"], -) - -cc_proto_library( - name = "field_mask_cc_proto", - testonly = 1, - deps = [":field_mask_proto"], -) - -proto_library( - name = "maps_proto", - testonly = 1, - srcs = ["testdata/maps.proto"], - strip_import_prefix = "/src", - deps = ["//:any_proto"], -) - -cc_proto_library( - name = "maps_cc_proto", - testonly = 1, - deps = [":maps_proto"], -) - -proto_library( - name = "oneofs_proto", - testonly = 1, - srcs = ["testdata/oneofs.proto"], - strip_import_prefix = "/src", - deps = [ - "//:any_proto", - "//:struct_proto", - "//:timestamp_proto", - ], -) - -cc_proto_library( - name = "oneofs_cc_proto", - testonly = 1, - deps = [":oneofs_proto"], -) - -proto_library( - name = "proto3_proto", - testonly = 1, - srcs = ["testdata/proto3.proto"], - strip_import_prefix = "/src", -) - -cc_proto_library( - name = "proto3_cc_proto", - testonly = 1, - deps = [":proto3_proto"], -) - -proto_library( - name = "struct_proto", - testonly = 1, - srcs = ["testdata/struct.proto"], - strip_import_prefix = "/src", - deps = ["//:struct_proto"], -) - -cc_proto_library( - name = "struct_cc_proto", - testonly = 1, - deps = [":struct_proto"], -) - -proto_library( - name = "timestamp_duration_proto", - testonly = 1, - srcs = ["testdata/timestamp_duration.proto"], - strip_import_prefix = "/src", - deps = [ - "//:duration_proto", - "//:timestamp_proto", - ], -) - -cc_proto_library( - name = "timestamp_duration_cc_proto", - testonly = 1, - deps = [":timestamp_duration_proto"], -) - -proto_library( - name = "wrappers_proto", - testonly = 1, - srcs = ["testdata/wrappers.proto"], - strip_import_prefix = "/src", - deps = ["//:wrappers_proto"], -) - -cc_proto_library( - name = "wrappers_cc_proto", - testonly = 1, - deps = [":wrappers_proto"], -) - -################################################################################ -# Distribution packaging -################################################################################ - -pkg_files( - name = "dist_files", - srcs = glob(["**/*"]), - strip_prefix = strip_prefix.from_root(""), - visibility = ["//src:__pkg__"], -) - -filegroup( - name = "test_srcs", - srcs = glob([ - "*_test.cc", - "*unittest.cc", - ]) + [ - "type_info_test_helper.cc", - ], -) - -filegroup( - name = "test_proto_srcs", - srcs = glob(["testdata/*.proto"]), -) diff --git a/src/google/protobuf/util/internal/constants.h b/src/google/protobuf/util/internal/constants.h deleted file mode 100644 index 7c81c47ddd..0000000000 --- a/src/google/protobuf/util/internal/constants.h +++ /dev/null @@ -1,101 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_CONSTANTS_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_CONSTANTS_H__ - -#include - -#include "google/protobuf/stubs/common.h" - -// This file contains constants used by //net/proto2/util/converter. - -namespace google { -namespace protobuf { -namespace util { -namespace converter { -// Prefix for type URLs. -const char kTypeServiceBaseUrl[] = "type.googleapis.com"; - -// Format string for RFC3339 timestamp formatting. -const char kRfc3339TimeFormat[] = "%E4Y-%m-%dT%H:%M:%S"; - -// Same as above, but the year value is not zero-padded i.e. this accepts -// timestamps like "1-01-0001T23:59:59Z" instead of "0001-01-0001T23:59:59Z". -const char kRfc3339TimeFormatNoPadding[] = "%Y-%m-%dT%H:%M:%S"; - -// Minimum seconds allowed in a google.protobuf.Timestamp value. -const int64_t kTimestampMinSeconds = -62135596800LL; - -// Maximum seconds allowed in a google.protobuf.Timestamp value. -const int64_t kTimestampMaxSeconds = 253402300799LL; - -// Minimum seconds allowed in a google.protobuf.Duration value. -const int64_t kDurationMinSeconds = -315576000000LL; - -// Maximum seconds allowed in a google.protobuf.Duration value. -const int64_t kDurationMaxSeconds = 315576000000LL; - -// Nano seconds in a second. -const int32_t kNanosPerSecond = 1000000000; - -// Type url representing NULL values in google.protobuf.Struct type. -const char kStructNullValueTypeUrl[] = - "type.googleapis.com/google.protobuf.NullValue"; - -// Type string for google.protobuf.Struct -const char kStructType[] = "google.protobuf.Struct"; - -// Type string for struct.proto's google.protobuf.Value value type. -const char kStructValueType[] = "google.protobuf.Value"; - -// Type string for struct.proto's google.protobuf.ListValue value type. -const char kStructListValueType[] = "google.protobuf.ListValue"; - -// Type string for google.protobuf.Timestamp -const char kTimestampType[] = "google.protobuf.Timestamp"; - -// Type string for google.protobuf.Duration -const char kDurationType[] = "google.protobuf.Duration"; - -// Type URL for struct value type google.protobuf.Value -const char kStructValueTypeUrl[] = "type.googleapis.com/google.protobuf.Value"; - -// Type string for google.protobuf.Any -const char kAnyType[] = "google.protobuf.Any"; - -// The protobuf option name of jspb.message_id; -const char kOptionJspbMessageId[] = "jspb.message_id"; - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_CONSTANTS_H__ diff --git a/src/google/protobuf/util/internal/datapiece.cc b/src/google/protobuf/util/internal/datapiece.cc deleted file mode 100644 index 7daed3f660..0000000000 --- a/src/google/protobuf/util/internal/datapiece.cc +++ /dev/null @@ -1,447 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google/protobuf/util/internal/datapiece.h" - -#include -#include -#include - -#include "google/protobuf/struct.pb.h" -#include "google/protobuf/type.pb.h" -#include "google/protobuf/descriptor.h" -#include "absl/status/status.h" -#include "absl/strings/ascii.h" -#include "absl/strings/escaping.h" -#include "absl/strings/str_cat.h" -#include "google/protobuf/util/internal/utility.h" -#include "google/protobuf/stubs/strutil.h" -#include "absl/strings/match.h" -#include "google/protobuf/stubs/mathutil.h" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -using ::absl::Status; - -namespace { - -template -absl::StatusOr ValidateNumberConversion(To after, From before) { - if (after == before && - MathUtil::Sign(before) == MathUtil::Sign(after)) { - return after; - } else { - return absl::InvalidArgumentError( - std::is_integral::value ? ValueAsString(before) - : std::is_same::value ? DoubleAsString(before) - : FloatAsString(before)); - } -} - -// For general conversion between -// int32, int64, uint32, uint64, double and float -// except conversion between double and float. -template -absl::StatusOr NumberConvertAndCheck(From before) { - if (std::is_same::value) return before; - - To after = static_cast(before); - return ValidateNumberConversion(after, before); -} - -// For conversion to integer types (int32, int64, uint32, uint64) from floating -// point types (double, float) only. -template -absl::StatusOr FloatingPointToIntConvertAndCheck(From before) { - if (std::is_same::value) return before; - - To after = static_cast(before); - return ValidateNumberConversion(after, before); -} - -// For conversion between double and float only. -absl::StatusOr FloatToDouble(float before) { - // Casting float to double should just work as double has more precision - // than float. - return static_cast(before); -} - -absl::StatusOr DoubleToFloat(double before) { - if (std::isnan(before)) { - return std::numeric_limits::quiet_NaN(); - } else if (!std::isfinite(before)) { - // Converting a double +inf/-inf to float should just work. - return static_cast(before); - } else if (before > std::numeric_limits::max() || - before < -std::numeric_limits::max()) { - // Some doubles are larger than the largest float, but after - // rounding they will be equal to the largest float. - // We can't just attempt the conversion because that has UB if - // the value really is out-of-range. - // Here we take advantage that 1/2-ing a large floating point - // will not lose precision. - double half_before = before * 0.5; - if (half_before < std::numeric_limits::max() && - half_before > -std::numeric_limits::max()) { - const float half_fmax = std::numeric_limits::max() * 0.5f; - // If after being cut in half, the value is less than the largest float, - // then it's safe to convert it to float. Importantly, this conversion - // rounds in the same way that the original does. - float half_after = static_cast(half_before); - if (half_after <= half_fmax && half_after >= -half_fmax) { - return half_after + half_after; - } - } - // Double value outside of the range of float. - return absl::InvalidArgumentError(DoubleAsString(before)); - } else { - return static_cast(before); - } -} - -} // namespace - -absl::StatusOr DataPiece::ToInt32() const { - if (type_ == TYPE_STRING) - return StringToNumber(safe_strto32); - - if (type_ == TYPE_DOUBLE) - return FloatingPointToIntConvertAndCheck(double_); - - if (type_ == TYPE_FLOAT) - return FloatingPointToIntConvertAndCheck(float_); - - return GenericConvert(); -} - -absl::StatusOr DataPiece::ToUint32() const { - if (type_ == TYPE_STRING) - return StringToNumber(safe_strtou32); - - if (type_ == TYPE_DOUBLE) - return FloatingPointToIntConvertAndCheck(double_); - - if (type_ == TYPE_FLOAT) - return FloatingPointToIntConvertAndCheck(float_); - - return GenericConvert(); -} - -absl::StatusOr DataPiece::ToInt64() const { - if (type_ == TYPE_STRING) - return StringToNumber(safe_strto64); - - if (type_ == TYPE_DOUBLE) - return FloatingPointToIntConvertAndCheck(double_); - - if (type_ == TYPE_FLOAT) - return FloatingPointToIntConvertAndCheck(float_); - - return GenericConvert(); -} - -absl::StatusOr DataPiece::ToUint64() const { - if (type_ == TYPE_STRING) - return StringToNumber(safe_strtou64); - - if (type_ == TYPE_DOUBLE) - return FloatingPointToIntConvertAndCheck(double_); - - if (type_ == TYPE_FLOAT) - return FloatingPointToIntConvertAndCheck(float_); - - return GenericConvert(); -} - -absl::StatusOr DataPiece::ToDouble() const { - if (type_ == TYPE_FLOAT) { - return FloatToDouble(float_); - } - if (type_ == TYPE_STRING) { - if (str_ == "Infinity") return std::numeric_limits::infinity(); - if (str_ == "-Infinity") return -std::numeric_limits::infinity(); - if (str_ == "NaN") return std::numeric_limits::quiet_NaN(); - absl::StatusOr value = StringToNumber(safe_strtod); - if (value.ok() && !std::isfinite(value.value())) { - // safe_strtod converts out-of-range values to +inf/-inf, but we want - // to report them as errors. - return absl::InvalidArgumentError(absl::StrCat("\"", str_, "\"")); - } else { - return value; - } - } - return GenericConvert(); -} - -absl::StatusOr DataPiece::ToFloat() const { - if (type_ == TYPE_DOUBLE) { - return DoubleToFloat(double_); - } - if (type_ == TYPE_STRING) { - if (str_ == "Infinity") return std::numeric_limits::infinity(); - if (str_ == "-Infinity") return -std::numeric_limits::infinity(); - if (str_ == "NaN") return std::numeric_limits::quiet_NaN(); - // SafeStrToFloat() is used instead of safe_strtof() because the later - // does not fail on inputs like SimpleDtoa(DBL_MAX). - return StringToNumber(SafeStrToFloat); - } - return GenericConvert(); -} - -absl::StatusOr DataPiece::ToBool() const { - switch (type_) { - case TYPE_BOOL: - return bool_; - case TYPE_STRING: - // Calls out to absl::SimpleAtob, which supports "true"/"false", - // "yes"/"no", "y"/"n", "t"/"f", and "1"/"0". - return StringToNumber(safe_strtob); - default: - break; - } - return absl::InvalidArgumentError( - ValueAsStringOrDefault("Wrong type. Cannot convert to Bool.")); -} - -absl::StatusOr DataPiece::ToString() const { - switch (type_) { - case TYPE_STRING: - return std::string(str_); - case TYPE_BYTES: { - std::string base64; - absl::Base64Escape(str_, &base64); - return base64; - } - default: - return absl::InvalidArgumentError( - ValueAsStringOrDefault("Cannot convert to string.")); - } -} - -std::string DataPiece::ValueAsStringOrDefault( - absl::string_view default_string) const { - switch (type_) { - case TYPE_INT32: - return absl::StrCat(i32_); - case TYPE_INT64: - return absl::StrCat(i64_); - case TYPE_UINT32: - return absl::StrCat(u32_); - case TYPE_UINT64: - return absl::StrCat(u64_); - case TYPE_DOUBLE: - return DoubleAsString(double_); - case TYPE_FLOAT: - return FloatAsString(float_); - case TYPE_BOOL: - return bool_ ? "true" : "false"; - case TYPE_STRING: - return absl::StrCat("\"", str_, "\""); - case TYPE_BYTES: { - std::string base64; - absl::WebSafeBase64Escape(str_, &base64); - return absl::StrCat("\"", base64, "\""); - } - case TYPE_NULL: - return "null"; - default: - return std::string(default_string); - } -} - -absl::StatusOr DataPiece::ToBytes() const { - if (type_ == TYPE_BYTES) return std::string(str_); - if (type_ == TYPE_STRING) { - std::string decoded; - if (!DecodeBase64(str_, &decoded)) { - return absl::InvalidArgumentError( - ValueAsStringOrDefault("Invalid data in input.")); - } - return decoded; - } else { - return absl::InvalidArgumentError(ValueAsStringOrDefault( - "Wrong type. Only String or Bytes can be converted to Bytes.")); - } -} - -absl::StatusOr DataPiece::ToEnum(const google::protobuf::Enum* enum_type, - bool use_lower_camel_for_enums, - bool case_insensitive_enum_parsing, - bool ignore_unknown_enum_values, - bool* is_unknown_enum_value) const { - if (type_ == TYPE_NULL) return google::protobuf::NULL_VALUE; - - if (type_ == TYPE_STRING) { - // First try the given value as a name. - std::string enum_name = std::string(str_); - const google::protobuf::EnumValue* value = - FindEnumValueByNameOrNull(enum_type, enum_name); - if (value != nullptr) return value->number(); - - // Check if int version of enum is sent as string. - absl::StatusOr int_value = ToInt32(); - if (int_value.ok()) { - if (const google::protobuf::EnumValue* enum_value = - FindEnumValueByNumberOrNull(enum_type, int_value.value())) { - return enum_value->number(); - } - } - - // Next try a normalized name. - bool should_normalize_enum = - case_insensitive_enum_parsing || use_lower_camel_for_enums; - if (should_normalize_enum) { - for (std::string::iterator it = enum_name.begin(); it != enum_name.end(); - ++it) { - *it = *it == '-' ? '_' : absl::ascii_toupper(*it); - } - value = FindEnumValueByNameOrNull(enum_type, enum_name); - if (value != nullptr) return value->number(); - } - - // If use_lower_camel_for_enums is true try with enum name without - // underscore. This will also accept camel case names as the enum_name has - // been normalized before. - if (use_lower_camel_for_enums) { - value = FindEnumValueByNameWithoutUnderscoreOrNull(enum_type, enum_name); - if (value != nullptr) return value->number(); - } - - // If ignore_unknown_enum_values is true an unknown enum value is ignored. - if (ignore_unknown_enum_values) { - *is_unknown_enum_value = true; - if (enum_type->enumvalue_size() > 0) { - return enum_type->enumvalue(0).number(); - } - } - } else { - // We don't need to check whether the value is actually declared in the - // enum because we preserve unknown enum values as well. - return ToInt32(); - } - return absl::InvalidArgumentError( - ValueAsStringOrDefault("Cannot find enum with given value.")); -} - -template -absl::StatusOr DataPiece::GenericConvert() const { - switch (type_) { - case TYPE_INT32: - return NumberConvertAndCheck(i32_); - case TYPE_INT64: - return NumberConvertAndCheck(i64_); - case TYPE_UINT32: - return NumberConvertAndCheck(u32_); - case TYPE_UINT64: - return NumberConvertAndCheck(u64_); - case TYPE_DOUBLE: - return NumberConvertAndCheck(double_); - case TYPE_FLOAT: - return NumberConvertAndCheck(float_); - default: // TYPE_ENUM, TYPE_STRING, TYPE_CORD, TYPE_BOOL - return absl::InvalidArgumentError(ValueAsStringOrDefault( - "Wrong type. Bool, Enum, String and Cord not supported in " - "GenericConvert.")); - } -} - -template -absl::StatusOr DataPiece::StringToNumber(bool (*func)(absl::string_view, - To*)) const { - if (str_.size() > 0 && (str_[0] == ' ' || str_[str_.size() - 1] == ' ')) { - return absl::InvalidArgumentError(absl::StrCat("\"", str_, "\"")); - } - To result; - if (func(str_, &result)) return result; - return absl::InvalidArgumentError( - absl::StrCat("\"", std::string(str_), "\"")); -} - -bool DataPiece::DecodeBase64(absl::string_view src, std::string* dest) const { - // Try web-safe decode first, if it fails, try the non-web-safe decode. - if (absl::WebSafeBase64Unescape(src, dest)) { - if (use_strict_base64_decoding_) { - // In strict mode, check if the escaped version gives us the same value as - // unescaped. - std::string encoded; - // WebSafeBase64Escape does no padding by default. - absl::WebSafeBase64Escape(*dest, &encoded); - // Remove trailing padding '=' characters before comparison. - absl::string_view src_no_padding = absl::string_view(src).substr( - 0, absl::EndsWith(src, "=") ? src.find_last_not_of('=') + 1 - : src.length()); - return encoded == src_no_padding; - } - return true; - } - - if (absl::Base64Unescape(src, dest)) { - if (use_strict_base64_decoding_) { - std::string encoded; - strings::LegacyBase64EscapeWithoutPadding(*dest, &encoded); - absl::string_view src_no_padding = absl::string_view(src).substr( - 0, absl::EndsWith(src, "=") ? src.find_last_not_of('=') + 1 - : src.length()); - return encoded == src_no_padding; - } - return true; - } - - return false; -} - -void DataPiece::InternalCopy(const DataPiece& other) { - type_ = other.type_; - use_strict_base64_decoding_ = other.use_strict_base64_decoding_; - switch (type_) { - case TYPE_INT32: - case TYPE_INT64: - case TYPE_UINT32: - case TYPE_UINT64: - case TYPE_DOUBLE: - case TYPE_FLOAT: - case TYPE_BOOL: - case TYPE_ENUM: - case TYPE_NULL: - case TYPE_BYTES: - case TYPE_STRING: { - str_ = other.str_; - break; - } - } -} - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/util/internal/datapiece.h b/src/google/protobuf/util/internal/datapiece.h deleted file mode 100644 index a69e8f00aa..0000000000 --- a/src/google/protobuf/util/internal/datapiece.h +++ /dev/null @@ -1,222 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_DATAPIECE_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_DATAPIECE_H__ - -#include -#include - -#include "google/protobuf/stubs/common.h" -#include "google/protobuf/stubs/logging.h" -#include "google/protobuf/type.pb.h" -#include "google/protobuf/port.h" -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" - -// Must be included last. -#include "google/protobuf/port_def.inc" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { -class ProtoWriter; - -// Container for a single piece of data together with its data type. -// -// For primitive types (int32, int64, uint32, uint64, double, float, bool), -// the data is stored by value. -// -// For string, an absl::string_view is stored. For Cord, a pointer to Cord is -// stored. Just like absl::string_view, the DataPiece class does not own the -// storage for the actual string or Cord, so it is the user's responsibility to -// guarantee that the underlying storage is still valid when the DataPiece is -// accessed. -class PROTOBUF_EXPORT DataPiece { - public: - // Identifies data type of the value. - // These are the types supported by DataPiece. - enum Type { - TYPE_INT32 = 1, - TYPE_INT64 = 2, - TYPE_UINT32 = 3, - TYPE_UINT64 = 4, - TYPE_DOUBLE = 5, - TYPE_FLOAT = 6, - TYPE_BOOL = 7, - TYPE_ENUM = 8, - TYPE_STRING = 9, - TYPE_BYTES = 10, - TYPE_NULL = 11, // explicit NULL type - }; - - // Constructors and Destructor - explicit DataPiece(const int32_t value) - : type_(TYPE_INT32), i32_(value), use_strict_base64_decoding_(false) {} - explicit DataPiece(const int64_t value) - : type_(TYPE_INT64), i64_(value), use_strict_base64_decoding_(false) {} - explicit DataPiece(const uint32_t value) - : type_(TYPE_UINT32), u32_(value), use_strict_base64_decoding_(false) {} - explicit DataPiece(const uint64_t value) - : type_(TYPE_UINT64), u64_(value), use_strict_base64_decoding_(false) {} - explicit DataPiece(const double value) - : type_(TYPE_DOUBLE), - double_(value), - use_strict_base64_decoding_(false) {} - explicit DataPiece(const float value) - : type_(TYPE_FLOAT), float_(value), use_strict_base64_decoding_(false) {} - explicit DataPiece(const bool value) - : type_(TYPE_BOOL), bool_(value), use_strict_base64_decoding_(false) {} - DataPiece(absl::string_view value, bool use_strict_base64_decoding) - : type_(TYPE_STRING), - str_(value), - use_strict_base64_decoding_(use_strict_base64_decoding) {} - // Constructor for bytes. The second parameter is not used. - DataPiece(absl::string_view value, bool /*dummy*/, - bool use_strict_base64_decoding) - : type_(TYPE_BYTES), - str_(value), - use_strict_base64_decoding_(use_strict_base64_decoding) {} - - DataPiece(const DataPiece& r) : type_(r.type_) { InternalCopy(r); } - - DataPiece& operator=(const DataPiece& x) { - InternalCopy(x); - return *this; - } - - static DataPiece NullData() { return DataPiece(TYPE_NULL, 0); } - - virtual ~DataPiece() { - } - - // Accessors - Type type() const { return type_; } - - bool use_strict_base64_decoding() { return use_strict_base64_decoding_; } - - absl::string_view str() const { - GOOGLE_LOG_IF(DFATAL, type_ != TYPE_STRING) << "Not a string type."; - return str_; - } - - - // Parses, casts or converts the value stored in the DataPiece into an int32. - absl::StatusOr ToInt32() const; - - // Parses, casts or converts the value stored in the DataPiece into a uint32. - absl::StatusOr ToUint32() const; - - // Parses, casts or converts the value stored in the DataPiece into an int64. - absl::StatusOr ToInt64() const; - - // Parses, casts or converts the value stored in the DataPiece into a uint64. - absl::StatusOr ToUint64() const; - - // Parses, casts or converts the value stored in the DataPiece into a double. - absl::StatusOr ToDouble() const; - - // Parses, casts or converts the value stored in the DataPiece into a float. - absl::StatusOr ToFloat() const; - - // Parses, casts or converts the value stored in the DataPiece into a bool. - absl::StatusOr ToBool() const; - - // Parses, casts or converts the value stored in the DataPiece into a string. - absl::StatusOr ToString() const; - - // Tries to convert the value contained in this datapiece to string. If the - // conversion fails, it returns the default_string. - std::string ValueAsStringOrDefault(absl::string_view default_string) const; - - absl::StatusOr ToBytes() const; - - private: - friend class ProtoWriter; - - // Disallow implicit constructor. - DataPiece(); - - // Helper to create NULL or ENUM types. - DataPiece(Type type, int32_t val) - : type_(type), i32_(val), use_strict_base64_decoding_(false) {} - - // Same as the ToEnum() method above but with additional flag to ignore - // unknown enum values. - absl::StatusOr ToEnum(const google::protobuf::Enum* enum_type, - bool use_lower_camel_for_enums, - bool case_insensitive_enum_parsing, - bool ignore_unknown_enum_values, - bool* is_unknown_enum_value) const; - - // For numeric conversion between - // int32, int64, uint32, uint64, double, float and bool - template - absl::StatusOr GenericConvert() const; - - // For conversion from string to - // int32, int64, uint32, uint64, double, float and bool - template - absl::StatusOr StringToNumber(bool (*func)(absl::string_view, To*)) const; - - // Decodes a base64 string. Returns true on success. - bool DecodeBase64(absl::string_view src, std::string* dest) const; - - // Helper function to initialize this DataPiece with 'other'. - void InternalCopy(const DataPiece& other); - - // Data type for this piece of data. - Type type_; - - // Stored piece of data. - union { - int32_t i32_; - int64_t i64_; - uint32_t u32_; - uint64_t u64_; - double double_; - float float_; - bool bool_; - absl::string_view str_; - }; - - // Uses a stricter version of base64 decoding for byte fields. - bool use_strict_base64_decoding_; -}; - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google - -#include "google/protobuf/port_undef.inc" - -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_DATAPIECE_H__ diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.cc b/src/google/protobuf/util/internal/default_value_objectwriter.cc deleted file mode 100644 index 05eccdf8d0..0000000000 --- a/src/google/protobuf/util/internal/default_value_objectwriter.cc +++ /dev/null @@ -1,640 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google/protobuf/util/internal/default_value_objectwriter.h" - -#include - -#include "absl/container/flat_hash_map.h" -#include "google/protobuf/util/internal/constants.h" -#include "google/protobuf/util/internal/utility.h" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -namespace { -// Helper function to convert string value to given data type by calling the -// passed converter function on the DataPiece created from "value" argument. -// If value is empty or if conversion fails, the default_value is returned. -template -T ConvertTo(absl::string_view value, - absl::StatusOr (DataPiece::*converter_fn)() const, - T default_value) { - if (value.empty()) return default_value; - absl::StatusOr result = (DataPiece(value, true).*converter_fn)(); - return result.ok() ? result.value() : default_value; -} -} // namespace - -DefaultValueObjectWriter::DefaultValueObjectWriter( - TypeResolver* type_resolver, const google::protobuf::Type& type, - ObjectWriter* ow) - : typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), - own_typeinfo_(true), - type_(type), - current_(nullptr), - root_(nullptr), - suppress_empty_list_(false), - preserve_proto_field_names_(false), - use_ints_for_enums_(false), - ow_(ow) {} - -DefaultValueObjectWriter::~DefaultValueObjectWriter() { - if (own_typeinfo_) { - delete typeinfo_; - } -} - -DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBool( - absl::string_view name, bool value) { - if (current_ == nullptr) { - ow_->RenderBool(name, value); - } else { - RenderDataPiece(name, DataPiece(value)); - } - return this; -} - -DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt32( - absl::string_view name, int32_t value) { - if (current_ == nullptr) { - ow_->RenderInt32(name, value); - } else { - RenderDataPiece(name, DataPiece(value)); - } - return this; -} - -DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint32( - absl::string_view name, uint32_t value) { - if (current_ == nullptr) { - ow_->RenderUint32(name, value); - } else { - RenderDataPiece(name, DataPiece(value)); - } - return this; -} - -DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt64( - absl::string_view name, int64_t value) { - if (current_ == nullptr) { - ow_->RenderInt64(name, value); - } else { - RenderDataPiece(name, DataPiece(value)); - } - return this; -} - -DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint64( - absl::string_view name, uint64_t value) { - if (current_ == nullptr) { - ow_->RenderUint64(name, value); - } else { - RenderDataPiece(name, DataPiece(value)); - } - return this; -} - -DefaultValueObjectWriter* DefaultValueObjectWriter::RenderDouble( - absl::string_view name, double value) { - if (current_ == nullptr) { - ow_->RenderDouble(name, value); - } else { - RenderDataPiece(name, DataPiece(value)); - } - return this; -} - -DefaultValueObjectWriter* DefaultValueObjectWriter::RenderFloat( - absl::string_view name, float value) { - if (current_ == nullptr) { - ow_->RenderBool(name, value); - } else { - RenderDataPiece(name, DataPiece(value)); - } - return this; -} - -DefaultValueObjectWriter* DefaultValueObjectWriter::RenderString( - absl::string_view name, absl::string_view value) { - if (current_ == nullptr) { - ow_->RenderString(name, value); - } else { - // Since absl::string_view is essentially a pointer, takes a copy of - // "value" to avoid ownership issues. - string_values_.emplace_back(new std::string(value)); - RenderDataPiece(name, DataPiece(*string_values_.back(), true)); - } - return this; -} - -DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes( - absl::string_view name, absl::string_view value) { - if (current_ == nullptr) { - ow_->RenderBytes(name, value); - } else { - // Since absl::string_view is essentially a pointer, takes a copy of - // "value" to avoid ownership issues. - string_values_.emplace_back(new std::string(value)); - RenderDataPiece(name, DataPiece(*string_values_.back(), false, true)); - } - return this; -} - -DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull( - absl::string_view name) { - if (current_ == nullptr) { - ow_->RenderNull(name); - } else { - RenderDataPiece(name, DataPiece::NullData()); - } - return this; -} - -void DefaultValueObjectWriter::RegisterFieldScrubCallBack( - FieldScrubCallBack field_scrub_callback) { - field_scrub_callback_ = std::move(field_scrub_callback); -} - -DefaultValueObjectWriter::Node* DefaultValueObjectWriter::CreateNewNode( - const std::string& name, const google::protobuf::Type* type, NodeKind kind, - const DataPiece& data, bool is_placeholder, - const std::vector& path, bool suppress_empty_list, - bool preserve_proto_field_names, bool use_ints_for_enums, - FieldScrubCallBack field_scrub_callback) { - return new Node(name, type, kind, data, is_placeholder, path, - suppress_empty_list, preserve_proto_field_names, - use_ints_for_enums, std::move(field_scrub_callback)); -} - -DefaultValueObjectWriter::Node::Node( - const std::string& name, const google::protobuf::Type* type, NodeKind kind, - const DataPiece& data, bool is_placeholder, - const std::vector& path, bool suppress_empty_list, - bool preserve_proto_field_names, bool use_ints_for_enums, - FieldScrubCallBack field_scrub_callback) - : name_(name), - type_(type), - kind_(kind), - is_any_(false), - data_(data), - is_placeholder_(is_placeholder), - path_(path), - suppress_empty_list_(suppress_empty_list), - preserve_proto_field_names_(preserve_proto_field_names), - use_ints_for_enums_(use_ints_for_enums), - field_scrub_callback_(std::move(field_scrub_callback)) {} - -DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild( - absl::string_view name) { - if (name.empty() || kind_ != OBJECT) { - return nullptr; - } - for (Node* child : children_) { - if (child->name() == name) { - return child; - } - } - return nullptr; -} - -void DefaultValueObjectWriter::Node::WriteTo(ObjectWriter* ow) { - if (kind_ == PRIMITIVE) { - ObjectWriter::RenderDataPieceTo(data_, name_, ow); - return; - } - - // Render maps. Empty maps are rendered as "{}". - if (kind_ == MAP) { - ow->StartObject(name_); - WriteChildren(ow); - ow->EndObject(); - return; - } - - // Write out lists. If we didn't have any list in response, write out empty - // list. - if (kind_ == LIST) { - // Suppress empty lists if requested. - if (suppress_empty_list_ && is_placeholder_) return; - - ow->StartList(name_); - WriteChildren(ow); - ow->EndList(); - return; - } - - // If is_placeholder_ = true, we didn't see this node in the response, so - // skip output. - if (is_placeholder_) return; - - ow->StartObject(name_); - WriteChildren(ow); - ow->EndObject(); -} - -void DefaultValueObjectWriter::Node::WriteChildren(ObjectWriter* ow) { - for (Node* child : children_) { - child->WriteTo(ow); - } -} - -const google::protobuf::Type* DefaultValueObjectWriter::Node::GetMapValueType( - const google::protobuf::Type& found_type, const TypeInfo* typeinfo) { - // If this field is a map, we should use the type of its "Value" as - // the type of the child node. - for (int i = 0; i < found_type.fields_size(); ++i) { - const google::protobuf::Field& sub_field = found_type.fields(i); - if (sub_field.number() != 2) { - continue; - } - if (sub_field.kind() != google::protobuf::Field::TYPE_MESSAGE) { - // This map's value type is not a message type. We don't need to - // get the field_type in this case. - break; - } - absl::StatusOr sub_type = - typeinfo->ResolveTypeUrl(sub_field.type_url()); - if (!sub_type.ok()) { - GOOGLE_LOG(WARNING) << "Cannot resolve type '" << sub_field.type_url() << "'."; - } else { - return sub_type.value(); - } - break; - } - return nullptr; -} - -void DefaultValueObjectWriter::Node::PopulateChildren( - const TypeInfo* typeinfo) { - // Ignores well known types that don't require automatically populating their - // primitive children. For type "Any", we only populate its children when the - // "@type" field is set. - // TODO(tsun): remove "kStructValueType" from the list. It's being checked - // now because of a bug in the tool-chain that causes the "oneof_index" - // of kStructValueType to not be set correctly. - if (type_ == nullptr || type_->name() == kAnyType || - type_->name() == kStructType || type_->name() == kTimestampType || - type_->name() == kDurationType || type_->name() == kStructValueType) { - return; - } - std::vector new_children; - absl::flat_hash_map orig_children_map; - - // Creates a map of child nodes to speed up lookup. - for (int i = 0; i < children_.size(); ++i) { - orig_children_map.try_emplace(children_[i]->name_, i); - } - - for (int i = 0; i < type_->fields_size(); ++i) { - const google::protobuf::Field& field = type_->fields(i); - - // This code is checking if the field to be added to the tree should be - // scrubbed or not by calling the field_scrub_callback_ callback function. - std::vector path; - if (!path_.empty()) { - path.insert(path.begin(), path_.begin(), path_.end()); - } - path.push_back(field.name()); - if (field_scrub_callback_ && field_scrub_callback_(path, &field)) { - continue; - } - - auto found = orig_children_map.find(field.name()); - // If the child field has already been set, we just add it to the new list - // of children. - if (found != orig_children_map.end()) { - new_children.push_back(children_[found->second]); - children_[found->second] = nullptr; - continue; - } - - const google::protobuf::Type* field_type = nullptr; - bool is_map = false; - NodeKind kind = PRIMITIVE; - - if (field.kind() == google::protobuf::Field::TYPE_MESSAGE) { - kind = OBJECT; - absl::StatusOr found_result = - typeinfo->ResolveTypeUrl(field.type_url()); - if (!found_result.ok()) { - // "field" is of an unknown type. - GOOGLE_LOG(WARNING) << "Cannot resolve type '" << field.type_url() << "'."; - } else { - const google::protobuf::Type* found_type = found_result.value(); - is_map = IsMap(field, *found_type); - - if (!is_map) { - field_type = found_type; - } else { - // If this field is a map, we should use the type of its "Value" as - // the type of the child node. - field_type = GetMapValueType(*found_type, typeinfo); - kind = MAP; - } - } - } - - if (!is_map && - field.cardinality() == google::protobuf::Field::CARDINALITY_REPEATED) { - kind = LIST; - } - - // If oneof_index() != 0, the child field is part of a "oneof", which means - // the child field is optional and we shouldn't populate its default - // primitive value. - if (field.oneof_index() != 0 && kind == PRIMITIVE) continue; - - // If the child field is of primitive type, sets its data to the default - // value of its type. - std::unique_ptr child( - new Node(preserve_proto_field_names_ ? field.name() : field.json_name(), - field_type, kind, - kind == PRIMITIVE ? CreateDefaultDataPieceForField( - field, typeinfo, use_ints_for_enums_) - : DataPiece::NullData(), - true, path, suppress_empty_list_, preserve_proto_field_names_, - use_ints_for_enums_, field_scrub_callback_)); - new_children.push_back(child.release()); - } - // Adds all leftover nodes in children_ to the beginning of new_child. - for (int i = 0; i < children_.size(); ++i) { - if (children_[i] == nullptr) { - continue; - } - new_children.insert(new_children.begin(), children_[i]); - children_[i] = nullptr; - } - children_.swap(new_children); -} - -void DefaultValueObjectWriter::MaybePopulateChildrenOfAny(Node* node) { - // If this is an "Any" node with "@type" already given and no other children - // have been added, populates its children. - if (node != nullptr && node->is_any() && node->type() != nullptr && - node->type()->name() != kAnyType && node->number_of_children() == 1) { - node->PopulateChildren(typeinfo_); - } -} - -DataPiece DefaultValueObjectWriter::FindEnumDefault( - const google::protobuf::Field& field, const TypeInfo* typeinfo, - bool use_ints_for_enums) { - const google::protobuf::Enum* enum_type = - typeinfo->GetEnumByTypeUrl(field.type_url()); - if (!enum_type) { - GOOGLE_LOG(WARNING) << "Could not find enum with type '" << field.type_url() - << "'"; - return DataPiece::NullData(); - } - if (!field.default_value().empty()) { - if (!use_ints_for_enums) { - return DataPiece(field.default_value(), true); - } else { - const std::string& enum_default_value_name = field.default_value(); - for (int enum_index = 0; enum_index < enum_type->enumvalue_size(); - ++enum_index) { - auto& enum_value = enum_type->enumvalue(enum_index); - if (enum_value.name() == enum_default_value_name) - return DataPiece(enum_value.number()); - } - GOOGLE_LOG(WARNING) << "Could not find enum value '" << enum_default_value_name - << "' with type '" << field.type_url() << "'"; - return DataPiece::NullData(); - } - } - // We treat the first value as the default if none is specified. - return enum_type->enumvalue_size() > 0 - ? (use_ints_for_enums - ? DataPiece(enum_type->enumvalue(0).number()) - : DataPiece(enum_type->enumvalue(0).name(), true)) - : DataPiece::NullData(); -} - -DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField( - const google::protobuf::Field& field, const TypeInfo* typeinfo, - bool use_ints_for_enums) { - switch (field.kind()) { - case google::protobuf::Field::TYPE_DOUBLE: { - return DataPiece(ConvertTo( - field.default_value(), &DataPiece::ToDouble, static_cast(0))); - } - case google::protobuf::Field::TYPE_FLOAT: { - return DataPiece(ConvertTo( - field.default_value(), &DataPiece::ToFloat, static_cast(0))); - } - case google::protobuf::Field::TYPE_INT64: - case google::protobuf::Field::TYPE_SINT64: - case google::protobuf::Field::TYPE_SFIXED64: { - return DataPiece(ConvertTo( - field.default_value(), &DataPiece::ToInt64, static_cast(0))); - } - case google::protobuf::Field::TYPE_UINT64: - case google::protobuf::Field::TYPE_FIXED64: { - return DataPiece(ConvertTo(field.default_value(), - &DataPiece::ToUint64, - static_cast(0))); - } - case google::protobuf::Field::TYPE_INT32: - case google::protobuf::Field::TYPE_SINT32: - case google::protobuf::Field::TYPE_SFIXED32: { - return DataPiece(ConvertTo( - field.default_value(), &DataPiece::ToInt32, static_cast(0))); - } - case google::protobuf::Field::TYPE_BOOL: { - return DataPiece( - ConvertTo(field.default_value(), &DataPiece::ToBool, false)); - } - case google::protobuf::Field::TYPE_STRING: { - return DataPiece(field.default_value(), true); - } - case google::protobuf::Field::TYPE_BYTES: { - return DataPiece(field.default_value(), false, true); - } - case google::protobuf::Field::TYPE_UINT32: - case google::protobuf::Field::TYPE_FIXED32: { - return DataPiece(ConvertTo(field.default_value(), - &DataPiece::ToUint32, - static_cast(0))); - } - case google::protobuf::Field::TYPE_ENUM: { - return FindEnumDefault(field, typeinfo, use_ints_for_enums); - } - default: { - return DataPiece::NullData(); - } - } -} - -DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( - absl::string_view name) { - if (current_ == nullptr) { - std::vector path; - root_.reset(CreateNewNode(std::string(name), &type_, OBJECT, - DataPiece::NullData(), false, path, - suppress_empty_list_, preserve_proto_field_names_, - use_ints_for_enums_, field_scrub_callback_)); - root_->PopulateChildren(typeinfo_); - current_ = root_.get(); - return this; - } - MaybePopulateChildrenOfAny(current_); - Node* child = current_->FindChild(name); - if (current_->kind() == LIST || current_->kind() == MAP || child == nullptr) { - // If current_ is a list or a map node, we should create a new child and use - // the type of current_ as the type of the new child. - std::unique_ptr node( - CreateNewNode(std::string(name), - ((current_->kind() == LIST || current_->kind() == MAP) - ? current_->type() - : nullptr), - OBJECT, DataPiece::NullData(), false, - child == nullptr ? current_->path() : child->path(), - suppress_empty_list_, preserve_proto_field_names_, - use_ints_for_enums_, field_scrub_callback_)); - child = node.get(); - current_->AddChild(node.release()); - } - - child->set_is_placeholder(false); - if (child->kind() == OBJECT && child->number_of_children() == 0) { - child->PopulateChildren(typeinfo_); - } - - stack_.push(current_); - current_ = child; - return this; -} - -DefaultValueObjectWriter* DefaultValueObjectWriter::EndObject() { - if (stack_.empty()) { - // The root object ends here. Writes out the tree. - WriteRoot(); - return this; - } - current_ = stack_.top(); - stack_.pop(); - return this; -} - -DefaultValueObjectWriter* DefaultValueObjectWriter::StartList( - absl::string_view name) { - if (current_ == nullptr) { - std::vector path; - root_.reset(CreateNewNode(std::string(name), &type_, LIST, - DataPiece::NullData(), false, path, - suppress_empty_list_, preserve_proto_field_names_, - use_ints_for_enums_, field_scrub_callback_)); - current_ = root_.get(); - return this; - } - MaybePopulateChildrenOfAny(current_); - Node* child = current_->FindChild(name); - if (child == nullptr || child->kind() != LIST) { - std::unique_ptr node(CreateNewNode( - std::string(name), nullptr, LIST, DataPiece::NullData(), false, - child == nullptr ? current_->path() : child->path(), - suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_, - field_scrub_callback_)); - child = node.get(); - current_->AddChild(node.release()); - } - child->set_is_placeholder(false); - - stack_.push(current_); - current_ = child; - return this; -} - -void DefaultValueObjectWriter::WriteRoot() { - root_->WriteTo(ow_); - root_.reset(nullptr); - current_ = nullptr; -} - -DefaultValueObjectWriter* DefaultValueObjectWriter::EndList() { - if (stack_.empty()) { - WriteRoot(); - return this; - } - current_ = stack_.top(); - stack_.pop(); - return this; -} - -void DefaultValueObjectWriter::RenderDataPiece(absl::string_view name, - const DataPiece& data) { - MaybePopulateChildrenOfAny(current_); - if (current_->type() != nullptr && current_->type()->name() == kAnyType && - name == "@type") { - absl::StatusOr data_string = data.ToString(); - if (data_string.ok()) { - const std::string& string_value = data_string.value(); - // If the type of current_ is "Any" and its "@type" field is being set - // here, sets the type of current_ to be the type specified by the - // "@type". - absl::StatusOr found_type = - typeinfo_->ResolveTypeUrl(string_value); - if (!found_type.ok()) { - GOOGLE_LOG(WARNING) << "Failed to resolve type '" << string_value << "'."; - } else { - current_->set_type(found_type.value()); - } - current_->set_is_any(true); - // If the "@type" field is placed after other fields, we should populate - // other children of primitive type now. Otherwise, we should wait until - // the first value field is rendered before we populate the children, - // because the "value" field of a Any message could be omitted. - if (current_->number_of_children() > 1 && current_->type() != nullptr) { - current_->PopulateChildren(typeinfo_); - } - } - } - Node* child = current_->FindChild(name); - if (child == nullptr || child->kind() != PRIMITIVE) { - // No children are found, creates a new child. - std::unique_ptr node( - CreateNewNode(std::string(name), nullptr, PRIMITIVE, data, false, - child == nullptr ? current_->path() : child->path(), - suppress_empty_list_, preserve_proto_field_names_, - use_ints_for_enums_, field_scrub_callback_)); - current_->AddChild(node.release()); - } else { - child->set_data(data); - child->set_is_placeholder(false); - } -} - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.h b/src/google/protobuf/util/internal/default_value_objectwriter.h deleted file mode 100644 index 2745159a0f..0000000000 --- a/src/google/protobuf/util/internal/default_value_objectwriter.h +++ /dev/null @@ -1,331 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_DEFAULT_VALUE_OBJECTWRITER_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_DEFAULT_VALUE_OBJECTWRITER_H__ - -#include -#include -#include -#include -#include - -#include "absl/strings/string_view.h" -#include "google/protobuf/port.h" -#include "google/protobuf/util/internal/datapiece.h" -#include "google/protobuf/util/internal/object_writer.h" -#include "google/protobuf/util/internal/type_info.h" -#include "google/protobuf/util/internal/utility.h" -#include "google/protobuf/util/type_resolver.h" - -// Must be included last. -#include "google/protobuf/port_def.inc" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -// An ObjectWriter that renders non-repeated primitive fields of proto messages -// with their default values. DefaultValueObjectWriter holds objects, lists and -// fields it receives in a tree structure and writes them out to another -// ObjectWriter when EndObject() is called on the root object. It also writes -// out all non-repeated primitive fields that haven't been explicitly rendered -// with their default values (0 for numbers, "" for strings, etc). -class PROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { - public: - // A Callback function to check whether a field needs to be scrubbed. - // - // Returns true if the field should not be present in the output. Returns - // false otherwise. - // - // The 'path' parameter is a vector of path to the field from root. For - // example: if a nested field "a.b.c" (b is the parent message field of c and - // a is the parent message field of b), then the vector should contain { "a", - // "b", "c" }. - // - // The Field* should point to the google::protobuf::Field of "c". - typedef std::function& /*path of the field*/, - const google::protobuf::Field* /*field*/)> - FieldScrubCallBack; - - DefaultValueObjectWriter(TypeResolver* type_resolver, - const google::protobuf::Type& type, - ObjectWriter* ow); - - DefaultValueObjectWriter(const DefaultValueObjectWriter&) = delete; - DefaultValueObjectWriter& operator=(const DefaultValueObjectWriter&) = delete; - ~DefaultValueObjectWriter() override; - - // ObjectWriter methods. - DefaultValueObjectWriter* StartObject(absl::string_view name) override; - - DefaultValueObjectWriter* EndObject() override; - - DefaultValueObjectWriter* StartList(absl::string_view name) override; - - DefaultValueObjectWriter* EndList() override; - - DefaultValueObjectWriter* RenderBool(absl::string_view name, - bool value) override; - - DefaultValueObjectWriter* RenderInt32(absl::string_view name, - int32_t value) override; - - DefaultValueObjectWriter* RenderUint32(absl::string_view name, - uint32_t value) override; - - DefaultValueObjectWriter* RenderInt64(absl::string_view name, - int64_t value) override; - - DefaultValueObjectWriter* RenderUint64(absl::string_view name, - uint64_t value) override; - - DefaultValueObjectWriter* RenderDouble(absl::string_view name, - double value) override; - - DefaultValueObjectWriter* RenderFloat(absl::string_view name, - float value) override; - - DefaultValueObjectWriter* RenderString(absl::string_view name, - absl::string_view value) override; - DefaultValueObjectWriter* RenderBytes(absl::string_view name, - absl::string_view value) override; - - DefaultValueObjectWriter* RenderNull(absl::string_view name) override; - - // Register the callback for scrubbing of fields. - void RegisterFieldScrubCallBack(FieldScrubCallBack field_scrub_callback); - - // If set to true, empty lists are suppressed from output when default values - // are written. - void set_suppress_empty_list(bool value) { suppress_empty_list_ = value; } - - // If set to true, original proto field names are used - void set_preserve_proto_field_names(bool value) { - preserve_proto_field_names_ = value; - } - - // If set to true, enums are rendered as ints from output when default values - // are written. - void set_print_enums_as_ints(bool value) { use_ints_for_enums_ = value; } - - protected: - enum NodeKind { - PRIMITIVE = 0, - OBJECT = 1, - LIST = 2, - MAP = 3, - }; - - // "Node" represents a node in the tree that holds the input of - // DefaultValueObjectWriter. - class PROTOBUF_EXPORT Node { - public: - Node(const std::string& name, const google::protobuf::Type* type, - NodeKind kind, const DataPiece& data, bool is_placeholder, - const std::vector& path, bool suppress_empty_list, - bool preserve_proto_field_names, bool use_ints_for_enums, - FieldScrubCallBack field_scrub_callback); - Node(const Node&) = delete; - Node& operator=(const Node&) = delete; - virtual ~Node() { - for (int i = 0; i < children_.size(); ++i) { - delete children_[i]; - } - } - - // Adds a child to this node. Takes ownership of this child. - void AddChild(Node* child) { children_.push_back(child); } - - // Finds the child given its name. - Node* FindChild(absl::string_view name); - - // Populates children of this Node based on its type. If there are already - // children created, they will be merged to the result. Caller should pass - // in TypeInfo for looking up types of the children. - virtual void PopulateChildren(const TypeInfo* typeinfo); - - // If this node is a leaf (has data), writes the current node to the - // ObjectWriter; if not, then recursively writes the children to the - // ObjectWriter. - virtual void WriteTo(ObjectWriter* ow); - - // Accessors - const std::string& name() const { return name_; } - - const std::vector& path() const { return path_; } - - const google::protobuf::Type* type() const { return type_; } - - void set_type(const google::protobuf::Type* type) { type_ = type; } - - NodeKind kind() const { return kind_; } - - int number_of_children() const { return children_.size(); } - - void set_data(const DataPiece& data) { data_ = data; } - - bool is_any() const { return is_any_; } - - void set_is_any(bool is_any) { is_any_ = is_any; } - - void set_is_placeholder(bool is_placeholder) { - is_placeholder_ = is_placeholder; - } - - protected: - // Returns the Value Type of a map given the Type of the map entry and a - // TypeInfo instance. - const google::protobuf::Type* GetMapValueType( - const google::protobuf::Type& found_type, const TypeInfo* typeinfo); - - // Calls WriteTo() on every child in children_. - void WriteChildren(ObjectWriter* ow); - - // The name of this node. - std::string name_; - // google::protobuf::Type of this node. Owned by TypeInfo. - const google::protobuf::Type* type_; - // The kind of this node. - NodeKind kind_; - // Whether this is a node for "Any". - bool is_any_; - // The data of this node when it is a leaf node. - DataPiece data_; - // Children of this node. - std::vector children_; - // Whether this node is a placeholder for an object or list automatically - // generated when creating the parent node. Should be set to false after - // the parent node's StartObject()/StartList() method is called with this - // node's name. - bool is_placeholder_; - - // Path of the field of this node - std::vector path_; - - // Whether to suppress empty list output. - bool suppress_empty_list_; - - // Whether to preserve original proto field names - bool preserve_proto_field_names_; - - // Whether to always print enums as ints - bool use_ints_for_enums_; - - // Function for determining whether a field needs to be scrubbed or not. - FieldScrubCallBack field_scrub_callback_; - }; - - // Creates a new Node and returns it. Caller owns memory of returned object. - virtual Node* CreateNewNode(const std::string& name, - const google::protobuf::Type* type, NodeKind kind, - const DataPiece& data, bool is_placeholder, - const std::vector& path, - bool suppress_empty_list, - bool preserve_proto_field_names, - bool use_ints_for_enums, - FieldScrubCallBack field_scrub_callback); - - // Creates a DataPiece containing the default value of the type of the field. - static DataPiece CreateDefaultDataPieceForField( - const google::protobuf::Field& field, const TypeInfo* typeinfo) { - return CreateDefaultDataPieceForField(field, typeinfo, false); - } - - // Same as the above but with a flag to use ints instead of enum names. - static DataPiece CreateDefaultDataPieceForField( - const google::protobuf::Field& field, const TypeInfo* typeinfo, - bool use_ints_for_enums); - - protected: - // Returns a pointer to current Node in tree. - Node* current() { return current_; } - - private: - // Populates children of "node" if it is an "any" Node and its real type has - // been given. - void MaybePopulateChildrenOfAny(Node* node); - - // Writes the root_ node to ow_ and resets the root_ and current_ pointer to - // nullptr. - void WriteRoot(); - - // Adds or replaces the data_ of a primitive child node. - void RenderDataPiece(absl::string_view name, const DataPiece& data); - - // Returns the default enum value as a DataPiece, or the first enum value if - // there is no default. For proto3, where we cannot specify an explicit - // default, a zero value will always be returned. - static DataPiece FindEnumDefault(const google::protobuf::Field& field, - const TypeInfo* typeinfo, - bool use_ints_for_enums); - - // Type information for all the types used in the descriptor. Used to find - // google::protobuf::Type of nested messages/enums. - const TypeInfo* typeinfo_; - // Whether the TypeInfo object is owned by this class. - bool own_typeinfo_; - // google::protobuf::Type of the root message type. - const google::protobuf::Type& type_; - // Holds copies of strings passed to RenderString. - std::vector> string_values_; - - // The current Node. Owned by its parents. - Node* current_; - // The root Node. - std::unique_ptr root_; - // The stack to hold the path of Nodes from current_ to root_; - std::stack stack_; - - // Whether to suppress output of empty lists. - bool suppress_empty_list_; - - // Whether to preserve original proto field names - bool preserve_proto_field_names_; - - // Whether to always print enums as ints - bool use_ints_for_enums_; - - // Function for determining whether a field needs to be scrubbed or not. - FieldScrubCallBack field_scrub_callback_; - - ObjectWriter* ow_; -}; - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google - -#include "google/protobuf/port_undef.inc" - -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_DEFAULT_VALUE_OBJECTWRITER_H__ diff --git a/src/google/protobuf/util/internal/default_value_objectwriter_test.cc b/src/google/protobuf/util/internal/default_value_objectwriter_test.cc deleted file mode 100644 index a8851b58bd..0000000000 --- a/src/google/protobuf/util/internal/default_value_objectwriter_test.cc +++ /dev/null @@ -1,191 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google/protobuf/util/internal/default_value_objectwriter.h" - -#include "google/protobuf/util/internal/expecting_objectwriter.h" -#include "google/protobuf/util/internal/constants.h" -#include "google/protobuf/util/internal/testdata/default_value_test.pb.h" -#include "google/protobuf/util/internal/type_info_test_helper.h" -#include - -namespace google { -namespace protobuf { -namespace util { -namespace converter { -namespace testing { - -using proto_util_converter::testing::DefaultValueTest; - -// Base class for setting up required state for running default values tests on -// different descriptors. -class BaseDefaultValueObjectWriterTest - : public ::testing::TestWithParam { - protected: - explicit BaseDefaultValueObjectWriterTest(const Descriptor* descriptor) - : helper_(GetParam()), mock_(), expects_(&mock_) { - helper_.ResetTypeInfo(descriptor); - testing_.reset(helper_.NewDefaultValueWriter( - std::string(kTypeServiceBaseUrl) + "/" + descriptor->full_name(), - &mock_)); - } - - ~BaseDefaultValueObjectWriterTest() override {} - - TypeInfoTestHelper helper_; - MockObjectWriter mock_; - ExpectingObjectWriter expects_; - std::unique_ptr testing_; -}; - -// Tests to cover some basic DefaultValueObjectWriter use cases. More tests are -// in the marshalling_test.cc and translator_integration_test.cc. -class DefaultValueObjectWriterTest : public BaseDefaultValueObjectWriterTest { - protected: - DefaultValueObjectWriterTest() - : BaseDefaultValueObjectWriterTest(DefaultValueTest::descriptor()) {} - ~DefaultValueObjectWriterTest() override {} -}; - -INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest, - DefaultValueObjectWriterTest, - ::testing::Values( - testing::USE_TYPE_RESOLVER)); - -TEST_P(DefaultValueObjectWriterTest, Empty) { - // Set expectation - expects_.StartObject("") - ->RenderDouble("doubleValue", 0.0) - ->StartList("repeatedDouble") - ->EndList() - ->RenderFloat("floatValue", 0.0) - ->RenderInt64("int64Value", 0) - ->RenderUint64("uint64Value", 0) - ->RenderInt32("int32Value", 0) - ->RenderUint32("uint32Value", 0) - ->RenderBool("boolValue", false) - ->RenderString("stringValue", "") - ->RenderBytes("bytesValue", "") - ->RenderString("enumValue", "ENUM_FIRST") - ->EndObject(); - - // Actual testing - testing_->StartObject("")->EndObject(); -} - -TEST_P(DefaultValueObjectWriterTest, NonDefaultDouble) { - // Set expectation - expects_.StartObject("") - ->RenderDouble("doubleValue", 1.0) - ->StartList("repeatedDouble") - ->EndList() - ->RenderFloat("floatValue", 0.0) - ->RenderInt64("int64Value", 0) - ->RenderUint64("uint64Value", 0) - ->RenderInt32("int32Value", 0) - ->RenderUint32("uint32Value", 0) - ->RenderBool("boolValue", false) - ->RenderString("stringValue", "") - ->RenderString("enumValue", "ENUM_FIRST") - ->EndObject(); - - // Actual testing - testing_->StartObject("")->RenderDouble("doubleValue", 1.0)->EndObject(); -} - -TEST_P(DefaultValueObjectWriterTest, ShouldRetainUnknownField) { - // Set expectation - expects_.StartObject("") - ->RenderDouble("doubleValue", 1.0) - ->StartList("repeatedDouble") - ->EndList() - ->RenderFloat("floatValue", 0.0) - ->RenderInt64("int64Value", 0) - ->RenderUint64("uint64Value", 0) - ->RenderInt32("int32Value", 0) - ->RenderUint32("uint32Value", 0) - ->RenderBool("boolValue", false) - ->RenderString("stringValue", "") - ->RenderString("unknown", "abc") - ->StartObject("unknownObject") - ->RenderString("unknown", "def") - ->EndObject() - ->RenderString("enumValue", "ENUM_FIRST") - ->EndObject(); - - // Actual testing - testing_->StartObject("") - ->RenderDouble("doubleValue", 1.0) - ->RenderString("unknown", "abc") - ->StartObject("unknownObject") - ->RenderString("unknown", "def") - ->EndObject() - ->EndObject(); -} - - -class DefaultValueObjectWriterSuppressListTest - : public BaseDefaultValueObjectWriterTest { - protected: - DefaultValueObjectWriterSuppressListTest() - : BaseDefaultValueObjectWriterTest(DefaultValueTest::descriptor()) { - testing_->set_suppress_empty_list(true); - } - ~DefaultValueObjectWriterSuppressListTest() override {} -}; - -INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest, - DefaultValueObjectWriterSuppressListTest, - ::testing::Values( - testing::USE_TYPE_RESOLVER)); - -TEST_P(DefaultValueObjectWriterSuppressListTest, Empty) { - // Set expectation. Empty lists should be suppressed. - expects_.StartObject("") - ->RenderDouble("doubleValue", 0.0) - ->RenderFloat("floatValue", 0.0) - ->RenderInt64("int64Value", 0) - ->RenderUint64("uint64Value", 0) - ->RenderInt32("int32Value", 0) - ->RenderUint32("uint32Value", 0) - ->RenderBool("boolValue", false) - ->RenderString("stringValue", "") - ->RenderBytes("bytesValue", "") - ->RenderString("enumValue", "ENUM_FIRST") - ->EndObject(); - - // Actual testing - testing_->StartObject("")->EndObject(); -} -} // namespace testing -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/util/internal/error_listener.h b/src/google/protobuf/util/internal/error_listener.h deleted file mode 100644 index 27fb65cfe8..0000000000 --- a/src/google/protobuf/util/internal/error_listener.h +++ /dev/null @@ -1,107 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_ERROR_LISTENER_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_ERROR_LISTENER_H__ - -#include -#include -#include -#include - -#include "google/protobuf/stubs/callback.h" -#include "google/protobuf/stubs/common.h" -#include "google/protobuf/stubs/logging.h" -#include "absl/strings/string_view.h" -#include "google/protobuf/port.h" -#include "google/protobuf/util/internal/location_tracker.h" - -// Must be included last. -#include "google/protobuf/port_def.inc" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -// Interface for error listener. -class PROTOBUF_EXPORT ErrorListener { - public: - ErrorListener(const ErrorListener&) = delete; - ErrorListener& operator=(const ErrorListener&) = delete; - virtual ~ErrorListener() {} - - // Reports an invalid name at the given location. - virtual void InvalidName(const LocationTrackerInterface& loc, - absl::string_view invalid_name, - absl::string_view message) = 0; - - // Reports an invalid value for a field. - virtual void InvalidValue(const LocationTrackerInterface& loc, - absl::string_view type_name, - absl::string_view value) = 0; - - // Reports a missing required field. - virtual void MissingField(const LocationTrackerInterface& loc, - absl::string_view missing_name) = 0; - - protected: - ErrorListener() {} -}; - -// An error listener that ignores all errors. -class PROTOBUF_EXPORT NoopErrorListener : public ErrorListener { - public: - NoopErrorListener() {} - NoopErrorListener(const NoopErrorListener&) = delete; - NoopErrorListener& operator=(const NoopErrorListener&) = delete; - ~NoopErrorListener() override {} - - void InvalidName(const LocationTrackerInterface& /*loc*/, - absl::string_view /* invalid_name */, - absl::string_view /* message */) override {} - - void InvalidValue(const LocationTrackerInterface& /*loc*/, - absl::string_view /* type_name */, - absl::string_view /* value */) override {} - - void MissingField(const LocationTrackerInterface& /* loc */, - absl::string_view /* missing_name */) override {} -}; - - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google - -#include "google/protobuf/port_undef.inc" - -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_ERROR_LISTENER_H__ diff --git a/src/google/protobuf/util/internal/expecting_objectwriter.h b/src/google/protobuf/util/internal/expecting_objectwriter.h deleted file mode 100644 index 8f200d55be..0000000000 --- a/src/google/protobuf/util/internal/expecting_objectwriter.h +++ /dev/null @@ -1,251 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_EXPECTING_OBJECTWRITER_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_EXPECTING_OBJECTWRITER_H__ - -// An implementation of ObjectWriter that automatically sets the -// gmock expectations for the response to a method. Every method -// returns the object itself for chaining. -// -// Usage: -// // Setup -// MockObjectWriter mock; -// ExpectingObjectWriter ow(&mock); -// -// // Set expectation -// ow.StartObject("") -// ->RenderString("key", "value") -// ->EndObject(); -// -// // Actual testing -// mock.StartObject(absl::string_view()) -// ->RenderString("key", "value") -// ->EndObject(); - -#include - -#include -#include "absl/strings/string_view.h" -#include "google/protobuf/port.h" -#include "google/protobuf/util/internal/object_writer.h" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -using testing::Eq; -using testing::IsEmpty; -using testing::NanSensitiveDoubleEq; -using testing::NanSensitiveFloatEq; -using testing::Return; -using testing::StrEq; -using testing::TypedEq; - -class MockObjectWriter : public ObjectWriter { - public: - MockObjectWriter() {} - - MOCK_METHOD(ObjectWriter*, StartObject, (absl::string_view), (override)); - MOCK_METHOD(ObjectWriter*, EndObject, (), (override)); - MOCK_METHOD(ObjectWriter*, StartList, (absl::string_view), (override)); - MOCK_METHOD(ObjectWriter*, EndList, (), (override)); - MOCK_METHOD(ObjectWriter*, RenderBool, (absl::string_view, bool), (override)); - MOCK_METHOD(ObjectWriter*, RenderInt32, (absl::string_view, int32_t), - (override)); - MOCK_METHOD(ObjectWriter*, RenderUint32, (absl::string_view, uint32_t), - (override)); - MOCK_METHOD(ObjectWriter*, RenderInt64, (absl::string_view, int64_t), - (override)); - MOCK_METHOD(ObjectWriter*, RenderUint64, (absl::string_view, uint64_t), - (override)); - MOCK_METHOD(ObjectWriter*, RenderDouble, (absl::string_view, double), - (override)); - MOCK_METHOD(ObjectWriter*, RenderFloat, (absl::string_view, float), - (override)); - MOCK_METHOD(ObjectWriter*, RenderString, - (absl::string_view, absl::string_view), (override)); - MOCK_METHOD(ObjectWriter*, RenderBytes, - (absl::string_view, absl::string_view), (override)); - MOCK_METHOD(ObjectWriter*, RenderNull, (absl::string_view), (override)); -}; - -class ExpectingObjectWriter : public ObjectWriter { - public: - explicit ExpectingObjectWriter(MockObjectWriter* mock) : mock_(mock) {} - ExpectingObjectWriter(const ExpectingObjectWriter&) = delete; - ExpectingObjectWriter& operator=(const ExpectingObjectWriter&) = delete; - - ObjectWriter* StartObject(absl::string_view name) override { - (name.empty() ? EXPECT_CALL(*mock_, StartObject(IsEmpty())) - : EXPECT_CALL(*mock_, StartObject(Eq(std::string(name))))) - .WillOnce(Return(mock_)) - .RetiresOnSaturation(); - return this; - } - - ObjectWriter* EndObject() override { - EXPECT_CALL(*mock_, EndObject()) - .WillOnce(Return(mock_)) - .RetiresOnSaturation(); - return this; - } - - ObjectWriter* StartList(absl::string_view name) override { - (name.empty() ? EXPECT_CALL(*mock_, StartList(IsEmpty())) - : EXPECT_CALL(*mock_, StartList(Eq(std::string(name))))) - .WillOnce(Return(mock_)) - .RetiresOnSaturation(); - return this; - } - - ObjectWriter* EndList() override { - EXPECT_CALL(*mock_, EndList()) - .WillOnce(Return(mock_)) - .RetiresOnSaturation(); - return this; - } - - ObjectWriter* RenderBool(absl::string_view name, bool value) override { - (name.empty() - ? EXPECT_CALL(*mock_, RenderBool(IsEmpty(), TypedEq(value))) - : EXPECT_CALL(*mock_, - RenderBool(Eq(std::string(name)), TypedEq(value)))) - .WillOnce(Return(mock_)) - .RetiresOnSaturation(); - return this; - } - - ObjectWriter* RenderInt32(absl::string_view name, int32_t value) override { - (name.empty() - ? EXPECT_CALL(*mock_, RenderInt32(IsEmpty(), TypedEq(value))) - : EXPECT_CALL(*mock_, RenderInt32(Eq(std::string(name)), - TypedEq(value)))) - .WillOnce(Return(mock_)) - .RetiresOnSaturation(); - return this; - } - - ObjectWriter* RenderUint32(absl::string_view name, uint32_t value) override { - (name.empty() ? EXPECT_CALL(*mock_, RenderUint32(IsEmpty(), - TypedEq(value))) - : EXPECT_CALL(*mock_, RenderUint32(Eq(std::string(name)), - TypedEq(value)))) - .WillOnce(Return(mock_)) - .RetiresOnSaturation(); - return this; - } - - ObjectWriter* RenderInt64(absl::string_view name, int64_t value) override { - (name.empty() - ? EXPECT_CALL(*mock_, RenderInt64(IsEmpty(), TypedEq(value))) - : EXPECT_CALL(*mock_, RenderInt64(Eq(std::string(name)), - TypedEq(value)))) - .WillOnce(Return(mock_)) - .RetiresOnSaturation(); - return this; - } - - ObjectWriter* RenderUint64(absl::string_view name, uint64_t value) override { - (name.empty() ? EXPECT_CALL(*mock_, RenderUint64(IsEmpty(), - TypedEq(value))) - : EXPECT_CALL(*mock_, RenderUint64(Eq(std::string(name)), - TypedEq(value)))) - .WillOnce(Return(mock_)) - .RetiresOnSaturation(); - return this; - } - - ObjectWriter* RenderDouble(absl::string_view name, double value) override { - (name.empty() - ? EXPECT_CALL(*mock_, - RenderDouble(IsEmpty(), NanSensitiveDoubleEq(value))) - : EXPECT_CALL(*mock_, RenderDouble(Eq(std::string(name)), - NanSensitiveDoubleEq(value)))) - .WillOnce(Return(mock_)) - .RetiresOnSaturation(); - return this; - } - - ObjectWriter* RenderFloat(absl::string_view name, float value) override { - (name.empty() - ? EXPECT_CALL(*mock_, - RenderFloat(IsEmpty(), NanSensitiveFloatEq(value))) - : EXPECT_CALL(*mock_, RenderFloat(Eq(std::string(name)), - NanSensitiveFloatEq(value)))) - .WillOnce(Return(mock_)) - .RetiresOnSaturation(); - return this; - } - - ObjectWriter* RenderString(absl::string_view name, - absl::string_view value) override { - (name.empty() ? EXPECT_CALL(*mock_, RenderString(IsEmpty(), - TypedEq( - std::string(value)))) - : EXPECT_CALL(*mock_, RenderString(Eq(std::string(name)), - TypedEq( - std::string(value))))) - .WillOnce(Return(mock_)) - .RetiresOnSaturation(); - return this; - } - ObjectWriter* RenderBytes(absl::string_view name, - absl::string_view value) override { - (name.empty() ? EXPECT_CALL(*mock_, RenderBytes(IsEmpty(), - TypedEq( - std::string(value)))) - : EXPECT_CALL(*mock_, RenderBytes(Eq(std::string(name)), - TypedEq( - std::string(value))))) - .WillOnce(Return(mock_)) - .RetiresOnSaturation(); - return this; - } - - ObjectWriter* RenderNull(absl::string_view name) override { - (name.empty() ? EXPECT_CALL(*mock_, RenderNull(IsEmpty())) - : EXPECT_CALL(*mock_, RenderNull(Eq(std::string(name)))) - .WillOnce(Return(mock_)) - .RetiresOnSaturation()); - return this; - } - - private: - MockObjectWriter* mock_; -}; - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google - -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_EXPECTING_OBJECTWRITER_H__ diff --git a/src/google/protobuf/util/internal/field_mask_utility.cc b/src/google/protobuf/util/internal/field_mask_utility.cc deleted file mode 100644 index 5cdc29da97..0000000000 --- a/src/google/protobuf/util/internal/field_mask_utility.cc +++ /dev/null @@ -1,219 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google/protobuf/util/internal/field_mask_utility.h" - -#include "absl/status/status.h" -#include "absl/strings/match.h" -#include "absl/strings/str_cat.h" -#include "google/protobuf/util/internal/utility.h" -#include "google/protobuf/stubs/status_macros.h" - -// Must be included last. -#include "google/protobuf/port_def.inc" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -namespace { - -// Appends a FieldMask path segment to a prefix. -std::string AppendPathSegmentToPrefix(absl::string_view prefix, - absl::string_view segment) { - if (prefix.empty()) { - return std::string(segment); - } - if (segment.empty()) { - return std::string(prefix); - } - // If the segment is a map key, appends it to the prefix without the ".". - if (absl::StartsWith(segment, "[\"")) { - return absl::StrCat(prefix, segment); - } - return absl::StrCat(prefix, ".", segment); -} - -} // namespace - -std::string ConvertFieldMaskPath(const absl::string_view path, - ConverterCallback converter) { - std::string result; - result.reserve(path.size() << 1); - - bool is_quoted = false; - bool is_escaping = false; - int current_segment_start = 0; - - // Loops until 1 passed the end of the input to make handling the last - // segment easier. - for (size_t i = 0; i <= path.size(); ++i) { - // Outputs quoted string as-is. - if (is_quoted) { - if (i == path.size()) { - break; - } - result.push_back(path[i]); - if (is_escaping) { - is_escaping = false; - } else if (path[i] == '\\') { - is_escaping = true; - } else if (path[i] == '\"') { - current_segment_start = i + 1; - is_quoted = false; - } - continue; - } - if (i == path.size() || path[i] == '.' || path[i] == '(' || - path[i] == ')' || path[i] == '\"') { - result += converter( - path.substr(current_segment_start, i - current_segment_start)); - if (i < path.size()) { - result.push_back(path[i]); - } - current_segment_start = i + 1; - } - if (i < path.size() && path[i] == '\"') { - is_quoted = true; - } - } - return result; -} - -absl::Status DecodeCompactFieldMaskPaths(absl::string_view paths, - PathSinkCallback path_sink) { - std::stack prefix; - int length = paths.length(); - int previous_position = 0; - bool in_map_key = false; - bool is_escaping = false; - // Loops until 1 passed the end of the input to make the handle of the last - // segment easier. - for (int i = 0; i <= length; ++i) { - if (i != length) { - // Skips everything in a map key until we hit the end of it, which is - // marked by an un-escaped '"' immediately followed by a ']'. - if (in_map_key) { - if (is_escaping) { - is_escaping = false; - continue; - } - if (paths[i] == '\\') { - is_escaping = true; - continue; - } - if (paths[i] != '\"') { - continue; - } - // Un-escaped '"' must be followed with a ']'. - if (i >= length - 1 || paths[i + 1] != ']') { - return absl::InvalidArgumentError(absl::StrCat( - "Invalid FieldMask '", paths, - "'. Map keys should be represented as [\"some_key\"].")); - } - // The end of the map key ("\"]") has been found. - in_map_key = false; - // Skips ']'. - i++; - // Checks whether the key ends at the end of a path segment. - if (i < length - 1 && paths[i + 1] != '.' && paths[i + 1] != ',' && - paths[i + 1] != ')' && paths[i + 1] != '(') { - return absl::InvalidArgumentError(absl::StrCat( - "Invalid FieldMask '", paths, - "'. Map keys should be at the end of a path segment.")); - } - is_escaping = false; - continue; - } - - // We are not in a map key, look for the start of one. - if (paths[i] == '[') { - if (i >= length - 1 || paths[i + 1] != '\"') { - return absl::InvalidArgumentError(absl::StrCat( - "Invalid FieldMask '", paths, - "'. Map keys should be represented as [\"some_key\"].")); - } - // "[\"" starts a map key. - in_map_key = true; - i++; // Skips the '\"'. - continue; - } - // If the current character is not a special character (',', '(' or ')'), - // continue to the next. - if (paths[i] != ',' && paths[i] != ')' && paths[i] != '(') { - continue; - } - } - // Gets the current segment - sub-string between previous position (after - // '(', ')', ',', or the beginning of the input) and the current position. - absl::string_view segment = - paths.substr(previous_position, i - previous_position); - std::string current_prefix = prefix.empty() ? "" : prefix.top(); - - if (i < length && paths[i] == '(') { - // Builds a prefix and save it into the stack. - prefix.push(AppendPathSegmentToPrefix(current_prefix, segment)); - } else if (!segment.empty()) { - // When the current character is ')', ',' or the current position has - // passed the end of the input, builds and outputs a new paths by - // concatenating the last prefix with the current segment. - RETURN_IF_ERROR( - path_sink(AppendPathSegmentToPrefix(current_prefix, segment))); - } - - // Removes the last prefix after seeing a ')'. - if (i < length && paths[i] == ')') { - if (prefix.empty()) { - return absl::InvalidArgumentError( - absl::StrCat("Invalid FieldMask '", paths, - "'. Cannot find matching '(' for all ')'.")); - } - prefix.pop(); - } - previous_position = i + 1; - } - if (in_map_key) { - return absl::InvalidArgumentError( - absl::StrCat("Invalid FieldMask '", paths, - "'. Cannot find matching ']' for all '['.")); - } - if (!prefix.empty()) { - return absl::InvalidArgumentError( - absl::StrCat("Invalid FieldMask '", paths, - "'. Cannot find matching ')' for all '('.")); - } - return absl::Status(); -} - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/util/internal/field_mask_utility.h b/src/google/protobuf/util/internal/field_mask_utility.h deleted file mode 100644 index 0db911a923..0000000000 --- a/src/google/protobuf/util/internal/field_mask_utility.h +++ /dev/null @@ -1,74 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// FieldMask related utility methods. - -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_FIELD_MASK_UTILITY_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_FIELD_MASK_UTILITY_H__ - -#include -#include - -#include "google/protobuf/stubs/callback.h" -#include "absl/status/status.h" -#include "absl/strings/string_view.h" -#include "google/protobuf/port.h" - - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -typedef std::function ConverterCallback; -typedef std::function PathSinkCallback; - -// Applies a 'converter' to each segment of a FieldMask path and returns the -// result. Quoted strings in the 'path' are copied to the output as-is without -// converting their content. Escaping is supported within quoted strings. -// For example, "ab\"_c" will be returned as "ab\"_c" without any changes. -std::string ConvertFieldMaskPath(const absl::string_view path, - ConverterCallback converter); - -// Decodes a compact list of FieldMasks. For example, "a.b,a.c.d,a.c.e" will be -// decoded into a list of field paths - "a.b", "a.c.d", "a.c.e". And the results -// will be sent to 'path_sink', i.e. 'path_sink' will be called once per -// resulting path. -// Note that we also support Apiary style FieldMask form. The above example in -// the Apiary style will look like "a.b,a.c(d,e)". -absl::Status DecodeCompactFieldMaskPaths(absl::string_view paths, - PathSinkCallback path_sink); - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google - -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_FIELD_MASK_UTILITY_H__ diff --git a/src/google/protobuf/util/internal/json_escaping.cc b/src/google/protobuf/util/internal/json_escaping.cc deleted file mode 100644 index 3cda95418e..0000000000 --- a/src/google/protobuf/util/internal/json_escaping.cc +++ /dev/null @@ -1,372 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google/protobuf/util/internal/json_escaping.h" - -#include - -#include "google/protobuf/stubs/logging.h" -#include "google/protobuf/stubs/common.h" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -namespace { - -// Array of hex characters for conversion to hex. -static const char kHex[] = "0123456789abcdef"; - -// Characters 0x00 to 0x9f are very commonly used, so we provide a special -// table lookup. -// -// For unicode code point ch < 0xa0: -// kCommonEscapes[ch] is the escaped string of ch, if escaping is needed; -// or an empty string, if escaping is not needed. -static const char kCommonEscapes[160][7] = { - // C0 (ASCII and derivatives) control characters - "\\u0000", "\\u0001", "\\u0002", "\\u0003", // 0x00 - "\\u0004", "\\u0005", "\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\u000b", - "\\f", "\\r", "\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012", - "\\u0013", // 0x10 - "\\u0014", "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", "\\u001a", - "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f", - // Escaping of " and \ are required by www.json.org string definition. - // Escaping of < and > are required for HTML security. - "", "", "\\\"", "", "", "", "", "", // 0x20 - "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", // 0x30 - "", "", "", "", "\\u003c", "", "\\u003e", "", "", "", "", "", "", "", "", - "", // 0x40 - "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", // 0x50 - "", "", "", "", "\\\\", "", "", "", "", "", "", "", "", "", "", "", // 0x60 - "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", // 0x70 - "", "", "", "", "", "", "", "\\u007f", - // C1 (ISO 8859 and Unicode) extended control characters - "\\u0080", "\\u0081", "\\u0082", "\\u0083", // 0x80 - "\\u0084", "\\u0085", "\\u0086", "\\u0087", "\\u0088", "\\u0089", "\\u008a", - "\\u008b", "\\u008c", "\\u008d", "\\u008e", "\\u008f", "\\u0090", "\\u0091", - "\\u0092", "\\u0093", // 0x90 - "\\u0094", "\\u0095", "\\u0096", "\\u0097", "\\u0098", "\\u0099", "\\u009a", - "\\u009b", "\\u009c", "\\u009d", "\\u009e", "\\u009f"}; - -// Determines if the given char value is a unicode surrogate code unit (either -// high-surrogate or low-surrogate). -inline bool IsSurrogate(uint32_t c) { - // Optimized form of: - // return c >= kMinHighSurrogate && c <= kMaxLowSurrogate; - // (Reduced from 3 ALU instructions to 2 ALU instructions) - return (c & 0xfffff800) == JsonEscaping::kMinHighSurrogate; -} - -// Returns true if the given unicode code point cp is a valid -// unicode code point (i.e. in the range 0 <= cp <= kMaxCodePoint). -inline bool IsValidCodePoint(uint32_t cp) { - return cp <= JsonEscaping::kMaxCodePoint; -} - -// Returns the low surrogate for the given unicode code point. The result is -// meaningless if the given code point is not a supplementary character. -inline uint16_t ToLowSurrogate(uint32_t cp) { - return (cp & - (JsonEscaping::kMaxLowSurrogate - JsonEscaping::kMinLowSurrogate)) + - JsonEscaping::kMinLowSurrogate; -} - -// Returns the high surrogate for the given unicode code point. The result is -// meaningless if the given code point is not a supplementary character. -inline uint16_t ToHighSurrogate(uint32_t cp) { - return (cp >> 10) + (JsonEscaping::kMinHighSurrogate - - (JsonEscaping::kMinSupplementaryCodePoint >> 10)); -} - -// Input str is encoded in UTF-8. A unicode code point could be encoded in -// UTF-8 using anywhere from 1 to 4 characters, and it could span multiple -// reads of the ByteSource. -// -// This function reads the next unicode code point from the input (str) at -// the given position (index), taking into account any left-over partial -// code point from the previous iteration (cp), together with the number -// of characters left to read to complete this code point (num_left). -// -// This function assumes that the input (str) is valid at the given position -// (index). In order words, at least one character could be read successfully. -// -// The code point read (partial or complete) is stored in (cp). Upon return, -// (num_left) stores the number of characters that has yet to be read in -// order to complete the current unicode code point. If the read is complete, -// then (num_left) is 0. Also, (num_read) is the number of characters read. -// -// Returns false if we encounter an invalid UTF-8 string. Returns true -// otherwise, including the case when we reach the end of the input (str) -// before a complete unicode code point is read. -bool ReadCodePoint(absl::string_view str, int index, uint32_t* cp, - int* num_left, int* num_read) { - if (*num_left == 0) { - // Last read was complete. Start reading a new unicode code point. - *cp = static_cast(str[index++]); - *num_read = 1; - // The length of the code point is determined from reading the first byte. - // - // If the first byte is between: - // 0..0x7f: that's the value of the code point. - // 0x80..0xbf: - // 0xc0..0xdf: 11-bit code point encoded in 2 bytes. - // bit 10-6, bit 5-0 - // 0xe0..0xef: 16-bit code point encoded in 3 bytes. - // bit 15-12, bit 11-6, bit 5-0 - // 0xf0..0xf7: 21-bit code point encoded in 4 bytes. - // bit 20-18, bit 17-12, bit 11-6, bit 5-0 - // 0xf8..0xff: - // - // Meaning of each bit: - // bit 7: 0 - single byte code point: bits 6-0 are values. - // 1 - multibyte code point - // bit 6: 0 - subsequent bytes of multibyte code point: - // bits 5-0 are values. - // 1 - first byte of multibyte code point - // bit 5: 0 - first byte of 2-byte code point: bits 4-0 are values. - // 1 - first byte of code point with >= 3 bytes. - // bit 4: 0 - first byte of 3-byte code point: bits 3-0 are values. - // 1 - first byte of code point with >= 4 bytes. - // bit 3: 0 - first byte of 4-byte code point: bits 2-0 are values. - // 1 - reserved for future expansion. - if (*cp <= 0x7f) { - return true; - } else if (*cp <= 0xbf) { - return false; - } else if (*cp <= 0xdf) { - *cp &= 0x1f; - *num_left = 1; - } else if (*cp <= 0xef) { - *cp &= 0x0f; - *num_left = 2; - } else if (*cp <= 0xf7) { - *cp &= 0x07; - *num_left = 3; - } else { - return false; - } - } else { - // Last read was partial. Initialize num_read to 0 and continue reading - // the last unicode code point. - *num_read = 0; - } - while (*num_left > 0 && index < str.size()) { - uint32_t ch = static_cast(str[index++]); - --(*num_left); - ++(*num_read); - *cp = (*cp << 6) | (ch & 0x3f); - if (ch < 0x80 || ch > 0xbf) return false; - } - return *num_left > 0 || (!IsSurrogate(*cp) && IsValidCodePoint(*cp)); -} - -// Stores the 16-bit unicode code point as its hexadecimal digits in buffer -// and returns an absl::string_view that points to this buffer. The input -// buffer needs to be at least 6 bytes long. -absl::string_view ToHex(uint16_t cp, char* buffer) { - buffer[5] = kHex[cp & 0x0f]; - cp >>= 4; - buffer[4] = kHex[cp & 0x0f]; - cp >>= 4; - buffer[3] = kHex[cp & 0x0f]; - cp >>= 4; - buffer[2] = kHex[cp & 0x0f]; - return absl::string_view(buffer, 6); -} - -// Stores the 32-bit unicode code point as its hexadecimal digits in buffer -// and returns an absl::string_view that points to this buffer. The input -// buffer needs to be at least 12 bytes long. -absl::string_view ToSurrogateHex(uint32_t cp, char* buffer) { - uint16_t low = ToLowSurrogate(cp); - uint16_t high = ToHighSurrogate(cp); - - buffer[11] = kHex[low & 0x0f]; - low >>= 4; - buffer[10] = kHex[low & 0x0f]; - low >>= 4; - buffer[9] = kHex[low & 0x0f]; - low >>= 4; - buffer[8] = kHex[low & 0x0f]; - - buffer[5] = kHex[high & 0x0f]; - high >>= 4; - buffer[4] = kHex[high & 0x0f]; - high >>= 4; - buffer[3] = kHex[high & 0x0f]; - high >>= 4; - buffer[2] = kHex[high & 0x0f]; - - return absl::string_view(buffer, 12); -} - -// If the given unicode code point needs escaping, then returns the escaped -// form. The returned absl::string_view either points to statically -// pre-allocated char[] or to the given buffer. The input buffer needs to be at -// least 12 bytes long. -// -// If the given unicode code point does not need escaping, an empty string is -// returned. -absl::string_view EscapeCodePoint(uint32_t cp, char* buffer) { - if (cp < 0xa0) return kCommonEscapes[cp]; - switch (cp) { - // These are not required by json spec - // but used to prevent security bugs in javascript. - case 0xfeff: // Zero width no-break space - case 0xfff9: // Interlinear annotation anchor - case 0xfffa: // Interlinear annotation separator - case 0xfffb: // Interlinear annotation terminator - - case 0x00ad: // Soft-hyphen - case 0x06dd: // Arabic end of ayah - case 0x070f: // Syriac abbreviation mark - case 0x17b4: // Khmer vowel inherent Aq - case 0x17b5: // Khmer vowel inherent Aa - return ToHex(cp, buffer); - - default: - if ((cp >= 0x0600 && cp <= 0x0603) || // Arabic signs - (cp >= 0x200b && cp <= 0x200f) || // Zero width etc. - (cp >= 0x2028 && cp <= 0x202e) || // Separators etc. - (cp >= 0x2060 && cp <= 0x2064) || // Invisible etc. - (cp >= 0x206a && cp <= 0x206f)) { // Shaping etc. - return ToHex(cp, buffer); - } - - if (cp == 0x000e0001 || // Language tag - (cp >= 0x0001d173 && cp <= 0x0001d17a) || // Music formatting - (cp >= 0x000e0020 && cp <= 0x000e007f)) { // TAG symbols - return ToSurrogateHex(cp, buffer); - } - } - return absl::string_view(); -} - -// Tries to escape the given code point first. If the given code point -// does not need to be escaped, but force_output is true, then render -// the given multi-byte code point in UTF8 in the buffer and returns it. -absl::string_view EscapeCodePoint(uint32_t cp, char* buffer, - bool force_output) { - absl::string_view sp = EscapeCodePoint(cp, buffer); - if (force_output && sp.empty()) { - buffer[5] = (cp & 0x3f) | 0x80; - cp >>= 6; - if (cp <= 0x1f) { - buffer[4] = cp | 0xc0; - sp = absl::string_view(buffer + 4, 2); - return sp; - } - buffer[4] = (cp & 0x3f) | 0x80; - cp >>= 6; - if (cp <= 0x0f) { - buffer[3] = cp | 0xe0; - sp = absl::string_view(buffer + 3, 3); - return sp; - } - buffer[3] = (cp & 0x3f) | 0x80; - buffer[2] = ((cp >> 6) & 0x07) | 0xf0; - sp = absl::string_view(buffer + 2, 4); - } - return sp; -} - -} // namespace - -void JsonEscaping::Escape(strings::ByteSource* input, - strings::ByteSink* output) { - char buffer[12] = "\\udead\\ubee"; - uint32_t cp = 0; // Current unicode code point. - int num_left = 0; // Num of chars to read to complete the code point. - while (input->Available() > 0) { - absl::string_view str = input->Peek(); - absl::string_view escaped; - int i = 0; - int num_read; - bool ok; - bool cp_was_split = num_left > 0; - // Loop until we encounter either - // i) a code point that needs to be escaped; or - // ii) a split code point is completely read; or - // iii) a character that is not a valid utf8; or - // iv) end of the string is reached. - do { - ok = ReadCodePoint(str, i, &cp, &num_left, &num_read); - if (num_left > 0 || !ok) break; // case iii or iv - escaped = EscapeCodePoint(cp, buffer, cp_was_split); - if (!escaped.empty()) break; // case i or ii - i += num_read; - num_read = 0; - } while (i < str.length()); // case iv - // First copy the un-escaped prefix, if any, to the output ByteSink. - if (i > 0) input->CopyTo(output, i); - if (num_read > 0) input->Skip(num_read); - if (!ok) { - // Case iii: Report error. - // TODO(wpoon): Add error reporting. - num_left = 0; - } else if (num_left == 0 && !escaped.empty()) { - // Case i or ii: Append the escaped code point to the output ByteSink. - output->Append(escaped.data(), escaped.size()); - } - } - if (num_left > 0) { - // Treat as case iii: report error. - // TODO(wpoon): Add error reporting. - } -} - -void JsonEscaping::Escape(absl::string_view input, strings::ByteSink* output) { - const size_t len = input.length(); - const char* p = input.data(); - - bool can_skip_escaping = true; - for (int i = 0; i < len; i++) { - char c = p[i]; - if (c < 0x20 || c >= 0x7F || c == '"' || c == '<' || c == '>' || - c == '\\') { - can_skip_escaping = false; - break; - } - } - - if (can_skip_escaping) { - output->Append(input.data(), input.length()); - } else { - strings::ArrayByteSource source(input); - Escape(&source, output); - } -} - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/util/internal/json_escaping.h b/src/google/protobuf/util/internal/json_escaping.h deleted file mode 100644 index 98b0e5be68..0000000000 --- a/src/google/protobuf/util/internal/json_escaping.h +++ /dev/null @@ -1,98 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_ESCAPING_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_ESCAPING_H__ - -#include - -#include "google/protobuf/stubs/common.h" -#include "google/protobuf/stubs/bytestream.h" -#include "google/protobuf/port.h" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -class JsonEscaping { - public: - // The minimum value of a unicode high-surrogate code unit in the utf-16 - // encoding. A high-surrogate is also known as a leading-surrogate. - // See http://www.unicode.org/glossary/#high_surrogate_code_unit - static constexpr uint16_t kMinHighSurrogate = 0xd800; - - // The maximum value of a unicide high-surrogate code unit in the utf-16 - // encoding. A high-surrogate is also known as a leading-surrogate. - // See http://www.unicode.org/glossary/#high_surrogate_code_unit - static constexpr uint16_t kMaxHighSurrogate = 0xdbff; - - // The minimum value of a unicode low-surrogate code unit in the utf-16 - // encoding. A low-surrogate is also known as a trailing-surrogate. - // See http://www.unicode.org/glossary/#low_surrogate_code_unit - static constexpr uint16_t kMinLowSurrogate = 0xdc00; - - // The maximum value of a unicode low-surrogate code unit in the utf-16 - // encoding. A low-surrogate is also known as a trailing surrogate. - // See http://www.unicode.org/glossary/#low_surrogate_code_unit - static constexpr uint16_t kMaxLowSurrogate = 0xdfff; - - // The minimum value of a unicode supplementary code point. - // See http://www.unicode.org/glossary/#supplementary_code_point - static constexpr uint32_t kMinSupplementaryCodePoint = 0x010000; - - // The minimum value of a unicode code point. - // See http://www.unicode.org/glossary/#code_point - static constexpr uint32_t kMinCodePoint = 0x000000; - - // The maximum value of a unicode code point. - // See http://www.unicode.org/glossary/#code_point - static constexpr uint32_t kMaxCodePoint = 0x10ffff; - - JsonEscaping() {} - JsonEscaping(const JsonEscaping&) = delete; - JsonEscaping& operator=(const JsonEscaping&) = delete; - virtual ~JsonEscaping() {} - - // Escape the given ByteSource to the given ByteSink. - static void Escape(strings::ByteSource* input, strings::ByteSink* output); - - // Escape the given ByteSource to the given ByteSink. - // This is optimized for the case where the string is all printable 7-bit - // ASCII and does not contain a few other characters (such as quotes). - static void Escape(absl::string_view input, strings::ByteSink* output); -}; - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google - -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_ESCAPING_H__ diff --git a/src/google/protobuf/util/internal/json_objectwriter.cc b/src/google/protobuf/util/internal/json_objectwriter.cc deleted file mode 100644 index ad9f5a12aa..0000000000 --- a/src/google/protobuf/util/internal/json_objectwriter.cc +++ /dev/null @@ -1,192 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google/protobuf/util/internal/json_objectwriter.h" - -#include -#include -#include - -#include "google/protobuf/stubs/logging.h" -#include "google/protobuf/stubs/common.h" -#include "google/protobuf/stubs/strutil.h" -#include "absl/base/casts.h" -#include "absl/strings/escaping.h" -#include "absl/strings/str_cat.h" -#include "google/protobuf/util/internal/json_escaping.h" -#include "google/protobuf/util/internal/utility.h" - - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -JsonObjectWriter::~JsonObjectWriter() { - if (element_ && !element_->is_root()) { - GOOGLE_LOG(WARNING) << "JsonObjectWriter was not fully closed."; - } -} - -JsonObjectWriter* JsonObjectWriter::StartObject(absl::string_view name) { - WritePrefix(name); - WriteChar('{'); - PushObject(); - return this; -} - -JsonObjectWriter* JsonObjectWriter::EndObject() { - Pop(); - WriteChar('}'); - if (element() && element()->is_root()) NewLine(); - return this; -} - -JsonObjectWriter* JsonObjectWriter::StartList(absl::string_view name) { - WritePrefix(name); - WriteChar('['); - PushArray(); - return this; -} - -JsonObjectWriter* JsonObjectWriter::EndList() { - Pop(); - WriteChar(']'); - if (element()->is_root()) NewLine(); - return this; -} - -JsonObjectWriter* JsonObjectWriter::RenderBool(absl::string_view name, - bool value) { - return RenderSimple(name, value ? "true" : "false"); -} - -JsonObjectWriter* JsonObjectWriter::RenderInt32(absl::string_view name, - int32_t value) { - return RenderSimple(name, absl::StrCat(value)); -} - -JsonObjectWriter* JsonObjectWriter::RenderUint32(absl::string_view name, - uint32_t value) { - return RenderSimple(name, absl::StrCat(value)); -} - -JsonObjectWriter* JsonObjectWriter::RenderInt64(absl::string_view name, - int64_t value) { - WritePrefix(name); - WriteChar('"'); - WriteRawString(absl::StrCat(value)); - WriteChar('"'); - return this; -} - -JsonObjectWriter* JsonObjectWriter::RenderUint64(absl::string_view name, - uint64_t value) { - WritePrefix(name); - WriteChar('"'); - WriteRawString(absl::StrCat(value)); - WriteChar('"'); - return this; -} - -JsonObjectWriter* JsonObjectWriter::RenderDouble(absl::string_view name, - double value) { - if (std::isfinite(value)) { - return RenderSimple(name, SimpleDtoa(value)); - } - - // Render quoted with NaN/Infinity-aware DoubleAsString. - return RenderString(name, DoubleAsString(value)); -} - -JsonObjectWriter* JsonObjectWriter::RenderFloat(absl::string_view name, - float value) { - if (std::isfinite(value)) { - return RenderSimple(name, SimpleFtoa(value)); - } - - // Render quoted with NaN/Infinity-aware FloatAsString. - return RenderString(name, FloatAsString(value)); -} - -JsonObjectWriter* JsonObjectWriter::RenderString(absl::string_view name, - absl::string_view value) { - WritePrefix(name); - WriteChar('"'); - JsonEscaping::Escape(value, &sink_); - WriteChar('"'); - return this; -} - -JsonObjectWriter* JsonObjectWriter::RenderBytes(absl::string_view name, - absl::string_view value) { - WritePrefix(name); - std::string base64; - - if (use_websafe_base64_for_bytes_) - strings::WebSafeBase64EscapeWithPadding(value, &base64); - else - absl::Base64Escape(value, &base64); - - WriteChar('"'); - // TODO(wpoon): Consider a ByteSink solution that writes the base64 bytes - // directly to the stream, rather than first putting them - // into a string and then writing them to the stream. - stream_->WriteRaw(base64.data(), base64.size()); - WriteChar('"'); - return this; -} - -JsonObjectWriter* JsonObjectWriter::RenderNull(absl::string_view name) { - return RenderSimple(name, "null"); -} - -JsonObjectWriter* JsonObjectWriter::RenderNullAsEmpty(absl::string_view name) { - return RenderSimple(name, ""); -} - -void JsonObjectWriter::WritePrefix(absl::string_view name) { - bool not_first = !element()->is_first(); - if (not_first) WriteChar(','); - if (not_first || !element()->is_root()) NewLine(); - if (!name.empty() || element()->is_json_object()) { - WriteChar('"'); - if (!name.empty()) { - JsonEscaping::Escape(name, &sink_); - } - WriteRawString("\":"); - if (!indent_string_.empty()) WriteChar(' '); - } -} - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/util/internal/json_objectwriter.h b/src/google/protobuf/util/internal/json_objectwriter.h deleted file mode 100644 index 443cdb491f..0000000000 --- a/src/google/protobuf/util/internal/json_objectwriter.h +++ /dev/null @@ -1,279 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_OBJECTWRITER_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_OBJECTWRITER_H__ - -#include -#include -#include - -#include "google/protobuf/io/coded_stream.h" -#include "google/protobuf/stubs/bytestream.h" -#include "google/protobuf/util/internal/structured_objectwriter.h" - -// clang-format off -#include "google/protobuf/port_def.inc" -// clang-format on - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - - -// An ObjectWriter implementation that outputs JSON. This ObjectWriter -// supports writing a compact form or a pretty printed form. -// -// Sample usage: -// string output; -// StringOutputStream* str_stream = new StringOutputStream(&output); -// CodedOutputStream* out_stream = new CodedOutputStream(str_stream); -// JsonObjectWriter* ow = new JsonObjectWriter(" ", out_stream); -// ow->StartObject("") -// ->RenderString("name", "value") -// ->RenderString("emptystring", string()) -// ->StartObject("nested") -// ->RenderInt64("light", 299792458); -// ->RenderDouble("pi", 3.141592653589793); -// ->EndObject() -// ->StartList("empty") -// ->EndList() -// ->EndObject(); -// -// And then the output string would become: -// { -// "name": "value", -// "emptystring": "", -// "nested": { -// "light": "299792458", -// "pi": 3.141592653589793 -// }, -// "empty": [] -// } -// -// JsonObjectWriter does not validate if calls actually result in valid JSON. -// For example, passing an empty name when one would be required won't result -// in an error, just an invalid output. -// -// Note that all int64 and uint64 are rendered as strings instead of numbers. -// This is because JavaScript parses numbers as 64-bit float thus int64 and -// uint64 would lose precision if rendered as numbers. -// -// JsonObjectWriter is thread-unsafe. -class PROTOBUF_EXPORT JsonObjectWriter : public StructuredObjectWriter { - public: - JsonObjectWriter(absl::string_view indent_string, io::CodedOutputStream* out) - : element_(new Element(/*parent=*/nullptr, /*is_json_object=*/false)), - stream_(out), - sink_(out), - indent_string_(indent_string), - indent_char_('\0'), - indent_count_(0), - use_websafe_base64_for_bytes_(false) { - // See if we have a trivial sequence of indent characters. - if (!indent_string.empty()) { - indent_char_ = indent_string[0]; - indent_count_ = indent_string.length(); - for (int i = 1; i < indent_string.length(); i++) { - if (indent_char_ != indent_string_[i]) { - indent_char_ = '\0'; - indent_count_ = 0; - break; - } - } - } - } - JsonObjectWriter(const JsonObjectWriter&) = delete; - JsonObjectWriter& operator=(const JsonObjectWriter&) = delete; - ~JsonObjectWriter() override; - - // ObjectWriter methods. - JsonObjectWriter* StartObject(absl::string_view name) override; - JsonObjectWriter* EndObject() override; - JsonObjectWriter* StartList(absl::string_view name) override; - JsonObjectWriter* EndList() override; - JsonObjectWriter* RenderBool(absl::string_view name, bool value) override; - JsonObjectWriter* RenderInt32(absl::string_view name, int32_t value) override; - JsonObjectWriter* RenderUint32(absl::string_view name, - uint32_t value) override; - JsonObjectWriter* RenderInt64(absl::string_view name, int64_t value) override; - JsonObjectWriter* RenderUint64(absl::string_view name, - uint64_t value) override; - JsonObjectWriter* RenderDouble(absl::string_view name, double value) override; - JsonObjectWriter* RenderFloat(absl::string_view name, float value) override; - JsonObjectWriter* RenderString(absl::string_view name, - absl::string_view value) override; - JsonObjectWriter* RenderBytes(absl::string_view name, - absl::string_view value) override; - JsonObjectWriter* RenderNull(absl::string_view name) override; - virtual JsonObjectWriter* RenderNullAsEmpty(absl::string_view name); - - void set_use_websafe_base64_for_bytes(bool value) { - use_websafe_base64_for_bytes_ = value; - } - - protected: - class PROTOBUF_EXPORT Element : public BaseElement { - public: - Element(Element* parent, bool is_json_object) - : BaseElement(parent), - is_first_(true), - is_json_object_(is_json_object) {} - Element(const Element&) = delete; - Element& operator=(const Element&) = delete; - - // Called before each field of the Element is to be processed. - // Returns true if this is the first call (processing the first field). - bool is_first() { - if (is_first_) { - is_first_ = false; - return true; - } - return false; - } - - // Whether we are currently rendering inside a JSON object (i.e., between - // StartObject() and EndObject()). - bool is_json_object() const { return is_json_object_; } - - private: - bool is_first_; - bool is_json_object_; - }; - - Element* element() override { return element_.get(); } - - private: - class PROTOBUF_EXPORT ByteSinkWrapper : public strings::ByteSink { - public: - explicit ByteSinkWrapper(io::CodedOutputStream* stream) : stream_(stream) {} - ByteSinkWrapper(const ByteSinkWrapper&) = delete; - ByteSinkWrapper& operator=(const ByteSinkWrapper&) = delete; - ~ByteSinkWrapper() override {} - - // ByteSink methods. - void Append(const char* bytes, size_t n) override { - stream_->WriteRaw(bytes, n); - } - - private: - io::CodedOutputStream* stream_; - }; - - // Renders a simple value as a string. By default all non-string Render - // methods convert their argument to a string and call this method. This - // method can then be used to render the simple value without escaping it. - JsonObjectWriter* RenderSimple(absl::string_view name, - absl::string_view value) { - WritePrefix(name); - WriteRawString(value); - return this; - } - - // Pushes a new JSON array element to the stack. - void PushArray() { - element_.reset(new Element(element_.release(), /*is_json_object=*/false)); - } - - // Pushes a new JSON object element to the stack. - void PushObject() { - element_.reset(new Element(element_.release(), /*is_json_object=*/true)); - } - - // Pops an element off of the stack and deletes the popped element. - void Pop() { - bool needs_newline = !element_->is_first(); - element_.reset(element_->pop()); - if (needs_newline) NewLine(); - } - - // If pretty printing is enabled, this will write a newline to the output, - // followed by optional indentation. Otherwise this method is a noop. - void NewLine() { - if (!indent_string_.empty()) { - size_t len = sizeof('\n') + (indent_string_.size() * element()->level()); - - // Take the slow-path if we don't have sufficient characters remaining in - // our buffer or we have a non-trivial indent string which would prevent - // us from using memset. - uint8_t* out = nullptr; - if (indent_count_ > 0) { - out = stream_->GetDirectBufferForNBytesAndAdvance(len); - } - - if (out != nullptr) { - out[0] = '\n'; - memset(&out[1], indent_char_, len - 1); - } else { - // Slow path, no contiguous output buffer available. - WriteChar('\n'); - for (int i = 0; i < element()->level(); i++) { - stream_->WriteRaw(indent_string_.c_str(), indent_string_.length()); - } - } - } - } - - // Writes a prefix. This will write out any pretty printing and - // commas that are required, followed by the name and a ':' if - // the name is not null. - void WritePrefix(absl::string_view name); - - // Writes an individual character to the output. - void WriteChar(const char c) { stream_->WriteRaw(&c, sizeof(c)); } - - // Writes a string to the output. - void WriteRawString(absl::string_view s) { - stream_->WriteRaw(s.data(), s.length()); - } - - std::unique_ptr element_; - io::CodedOutputStream* stream_; - ByteSinkWrapper sink_; - const std::string indent_string_; - - // For the common case of indent being a single character repeated. - char indent_char_; - int indent_count_; - - // Whether to use regular or websafe base64 encoding for byte fields. Defaults - // to regular base64 encoding. - bool use_websafe_base64_for_bytes_; -}; - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google - -#include "google/protobuf/port_undef.inc" - -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_OBJECTWRITER_H__ diff --git a/src/google/protobuf/util/internal/json_objectwriter_test.cc b/src/google/protobuf/util/internal/json_objectwriter_test.cc deleted file mode 100644 index 33b24de2ca..0000000000 --- a/src/google/protobuf/util/internal/json_objectwriter_test.cc +++ /dev/null @@ -1,315 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google/protobuf/util/internal/json_objectwriter.h" - -#include - -#include "google/protobuf/io/zero_copy_stream_impl_lite.h" -#include -#include "google/protobuf/util/internal/utility.h" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -using io::CodedOutputStream; -using io::StringOutputStream; - -class JsonObjectWriterTest : public ::testing::Test { - protected: - JsonObjectWriterTest() - : str_stream_(new StringOutputStream(&output_)), - out_stream_(new CodedOutputStream(str_stream_)), - ow_(nullptr) {} - - ~JsonObjectWriterTest() override { delete ow_; } - - std::string CloseStreamAndGetString() { - delete out_stream_; - delete str_stream_; - return output_; - } - - std::string output_; - StringOutputStream* const str_stream_; - CodedOutputStream* const out_stream_; - JsonObjectWriter* ow_; -}; - -TEST_F(JsonObjectWriterTest, EmptyRootObject) { - ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartObject("")->EndObject(); - EXPECT_EQ("{}", CloseStreamAndGetString()); -} - -TEST_F(JsonObjectWriterTest, EmptyObject) { - ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartObject("") - ->RenderString("test", "value") - ->StartObject("empty") - ->EndObject() - ->EndObject(); - EXPECT_EQ("{\"test\":\"value\",\"empty\":{}}", CloseStreamAndGetString()); -} - -TEST_F(JsonObjectWriterTest, EmptyRootList) { - ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartList("")->EndList(); - EXPECT_EQ("[]", CloseStreamAndGetString()); -} - -TEST_F(JsonObjectWriterTest, EmptyList) { - ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartObject("") - ->RenderString("test", "value") - ->StartList("empty") - ->EndList() - ->EndObject(); - EXPECT_EQ("{\"test\":\"value\",\"empty\":[]}", CloseStreamAndGetString()); -} - -TEST_F(JsonObjectWriterTest, EmptyObjectKey) { - ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartObject("")->RenderString("", "value")->EndObject(); - EXPECT_EQ("{\"\":\"value\"}", CloseStreamAndGetString()); -} - -TEST_F(JsonObjectWriterTest, ObjectInObject) { - ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartObject("") - ->StartObject("nested") - ->RenderString("field", "value") - ->EndObject() - ->EndObject(); - EXPECT_EQ("{\"nested\":{\"field\":\"value\"}}", CloseStreamAndGetString()); -} - -TEST_F(JsonObjectWriterTest, ListInObject) { - ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartObject("") - ->StartList("nested") - ->RenderString("", "value") - ->EndList() - ->EndObject(); - EXPECT_EQ("{\"nested\":[\"value\"]}", CloseStreamAndGetString()); -} - -TEST_F(JsonObjectWriterTest, ObjectInList) { - ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartList("") - ->StartObject("") - ->RenderString("field", "value") - ->EndObject() - ->EndList(); - EXPECT_EQ("[{\"field\":\"value\"}]", CloseStreamAndGetString()); -} - -TEST_F(JsonObjectWriterTest, ListInList) { - ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartList("") - ->StartList("") - ->RenderString("", "value") - ->EndList() - ->EndList(); - EXPECT_EQ("[[\"value\"]]", CloseStreamAndGetString()); -} - -TEST_F(JsonObjectWriterTest, RenderPrimitives) { - ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartObject("") - ->RenderBool("bool", true) - ->RenderDouble("double", std::numeric_limits::max()) - ->RenderFloat("float", std::numeric_limits::max()) - ->RenderInt32("int", std::numeric_limits::min()) - ->RenderInt64("long", std::numeric_limits::min()) - ->RenderBytes("bytes", "abracadabra") - ->RenderString("string", "string") - ->RenderBytes("emptybytes", "") - ->RenderString("emptystring", std::string()) - ->EndObject(); - EXPECT_EQ( - "{\"bool\":true," - "\"double\":" + - ValueAsString(std::numeric_limits::max()) + - "," - "\"float\":" + - ValueAsString(std::numeric_limits::max()) + - "," - "\"int\":-2147483648," - "\"long\":\"-9223372036854775808\"," - "\"bytes\":\"YWJyYWNhZGFicmE=\"," - "\"string\":\"string\"," - "\"emptybytes\":\"\"," - "\"emptystring\":\"\"}", - CloseStreamAndGetString()); -} - -TEST_F(JsonObjectWriterTest, BytesEncodesAsNonWebSafeBase64) { - std::string s; - s.push_back('\377'); - s.push_back('\357'); - ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartObject("")->RenderBytes("bytes", s)->EndObject(); - // Non-web-safe would encode this as "/+8=" - EXPECT_EQ("{\"bytes\":\"/+8=\"}", CloseStreamAndGetString()); -} - -TEST_F(JsonObjectWriterTest, PrettyPrintList) { - ow_ = new JsonObjectWriter(" ", out_stream_); - ow_->StartObject("") - ->StartList("items") - ->RenderString("", "item1") - ->RenderString("", "item2") - ->RenderString("", "item3") - ->EndList() - ->StartList("empty") - ->EndList() - ->EndObject(); - EXPECT_EQ( - "{\n" - " \"items\": [\n" - " \"item1\",\n" - " \"item2\",\n" - " \"item3\"\n" - " ],\n" - " \"empty\": []\n" - "}\n", - CloseStreamAndGetString()); -} - -TEST_F(JsonObjectWriterTest, PrettyPrintObject) { - ow_ = new JsonObjectWriter(" ", out_stream_); - ow_->StartObject("") - ->StartObject("items") - ->RenderString("key1", "item1") - ->RenderString("key2", "item2") - ->RenderString("key3", "item3") - ->EndObject() - ->StartObject("empty") - ->EndObject() - ->EndObject(); - EXPECT_EQ( - "{\n" - " \"items\": {\n" - " \"key1\": \"item1\",\n" - " \"key2\": \"item2\",\n" - " \"key3\": \"item3\"\n" - " },\n" - " \"empty\": {}\n" - "}\n", - CloseStreamAndGetString()); -} - -TEST_F(JsonObjectWriterTest, PrettyPrintEmptyObjectInEmptyList) { - ow_ = new JsonObjectWriter(" ", out_stream_); - ow_->StartObject("") - ->StartList("list") - ->StartObject("") - ->EndObject() - ->EndList() - ->EndObject(); - EXPECT_EQ( - "{\n" - " \"list\": [\n" - " {}\n" - " ]\n" - "}\n", - CloseStreamAndGetString()); -} - -TEST_F(JsonObjectWriterTest, PrettyPrintDoubleIndent) { - ow_ = new JsonObjectWriter(" ", out_stream_); - ow_->StartObject("") - ->RenderBool("bool", true) - ->RenderInt32("int", 42) - ->EndObject(); - EXPECT_EQ( - "{\n" - " \"bool\": true,\n" - " \"int\": 42\n" - "}\n", - CloseStreamAndGetString()); -} - -TEST_F(JsonObjectWriterTest, StringsEscapedAndEnclosedInDoubleQuotes) { - ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartObject("")->RenderString("string", "'<>&\\\"\r\n")->EndObject(); - EXPECT_EQ("{\"string\":\"'\\u003c\\u003e&\\\\\\\"\\r\\n\"}", - CloseStreamAndGetString()); -} - -TEST_F(JsonObjectWriterTest, Stringification) { - ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartObject("") - ->RenderDouble("double_nan", std::numeric_limits::quiet_NaN()) - ->RenderFloat("float_nan", std::numeric_limits::quiet_NaN()) - ->RenderDouble("double_pos", std::numeric_limits::infinity()) - ->RenderFloat("float_pos", std::numeric_limits::infinity()) - ->RenderDouble("double_neg", -std::numeric_limits::infinity()) - ->RenderFloat("float_neg", -std::numeric_limits::infinity()) - ->EndObject(); - EXPECT_EQ( - "{\"double_nan\":\"NaN\"," - "\"float_nan\":\"NaN\"," - "\"double_pos\":\"Infinity\"," - "\"float_pos\":\"Infinity\"," - "\"double_neg\":\"-Infinity\"," - "\"float_neg\":\"-Infinity\"}", - CloseStreamAndGetString()); -} - -TEST_F(JsonObjectWriterTest, TestRegularByteEncoding) { - ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartObject("") - ->RenderBytes("bytes", "\x03\xef\xc0") - ->EndObject(); - - // Test that we get regular (non websafe) base64 encoding on byte fields by - // default. - EXPECT_EQ("{\"bytes\":\"A+/A\"}", CloseStreamAndGetString()); -} - -TEST_F(JsonObjectWriterTest, TestWebsafeByteEncoding) { - ow_ = new JsonObjectWriter("", out_stream_); - ow_->set_use_websafe_base64_for_bytes(true); - ow_->StartObject("") - ->RenderBytes("bytes", "\x03\xef\xc0\x10") - ->EndObject(); - - // Test that we get websafe base64 encoding when explicitly asked. - EXPECT_EQ("{\"bytes\":\"A-_AEA==\"}", CloseStreamAndGetString()); -} - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/util/internal/json_stream_parser.cc b/src/google/protobuf/util/internal/json_stream_parser.cc deleted file mode 100644 index c294009bc8..0000000000 --- a/src/google/protobuf/util/internal/json_stream_parser.cc +++ /dev/null @@ -1,1001 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google/protobuf/util/internal/json_stream_parser.h" - -#include -#include -#include -#include -#include -#include - -#include "google/protobuf/stubs/common.h" -#include "google/protobuf/stubs/logging.h" -#include "google/protobuf/stubs/strutil.h" -#include "absl/status/status.h" -#include "absl/strings/ascii.h" -#include "absl/strings/escaping.h" -#include "absl/strings/match.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/string_view.h" -#include "google/protobuf/util/internal/object_writer.h" -#include "google/protobuf/util/internal/json_escaping.h" - - -namespace google { -namespace protobuf { -namespace util { - -namespace converter { - -// Number of digits in an escaped UTF-16 code unit ('\\' 'u' X X X X) -static const int kUnicodeEscapedLength = 6; - -static const int kDefaultMaxRecursionDepth = 100; - -// These cannot be constexpr for portability with VS2015. -static const absl::string_view kKeywordTrue = "true"; -static const absl::string_view kKeywordFalse = "false"; -static const absl::string_view kKeywordNull = "null"; - -inline bool IsLetter(char c) { - return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || (c == '_') || - (c == '$'); -} - -inline bool IsAlphanumeric(char c) { - return IsLetter(c) || ('0' <= c && c <= '9'); -} - -// Indicates a character may not be part of an unquoted key. -inline bool IsKeySeparator(char c) { - return (absl::ascii_isspace(c) || c == '"' || c == '\'' || c == '{' || - c == '}' || c == '[' || c == ']' || c == ':' || c == ','); -} - -inline void ReplaceInvalidCodePoints(absl::string_view str, - const std::string& replacement, - std::string* dst) { - while (!str.empty()) { - int n_valid_bytes = internal::UTF8SpnStructurallyValid(str); - absl::string_view valid_part = str.substr(0, n_valid_bytes); - absl::StrAppend(dst, valid_part); - - if (n_valid_bytes == str.size()) { - break; - } - - // Append replacement value. - absl::StrAppend(dst, replacement); - - // Move past valid bytes + one invalid byte. - str.remove_prefix(n_valid_bytes + 1); - } -} - -static bool ConsumeKey(absl::string_view* input, absl::string_view* key) { - if (input->empty() || !IsLetter((*input)[0])) return false; - int len = 1; - for (; len < input->size(); ++len) { - if (!IsAlphanumeric((*input)[len])) { - break; - } - } - *key = absl::string_view(input->data(), len); - *input = absl::string_view(input->data() + len, input->size() - len); - return true; -} - -// Same as 'ConsumeKey', but allows a widened set of key characters. -static bool ConsumeKeyPermissive(absl::string_view* input, - absl::string_view* key) { - if (input->empty() || !IsLetter((*input)[0])) return false; - int len = 1; - for (; len < input->size(); ++len) { - if (IsKeySeparator((*input)[len])) { - break; - } - } - *key = absl::string_view(input->data(), len); - *input = absl::string_view(input->data() + len, input->size() - len); - return true; -} - -static bool MatchKey(absl::string_view input) { - return !input.empty() && IsLetter(input[0]); -} - -JsonStreamParser::JsonStreamParser(ObjectWriter* ow) - : ow_(ow), - stack_(), - leftover_(), - json_(), - p_(), - key_(), - key_storage_(), - finishing_(false), - seen_non_whitespace_(false), - allow_no_root_element_(false), - parsed_(), - parsed_storage_(), - string_open_(0), - chunk_storage_(), - coerce_to_utf8_(false), - utf8_replacement_character_(" "), - allow_empty_null_(false), - allow_permissive_key_naming_(false), - loose_float_number_conversion_(false), - recursion_depth_(0), - max_recursion_depth_(kDefaultMaxRecursionDepth) { - // Initialize the stack with a single value to be parsed. - stack_.push(VALUE); -} - -JsonStreamParser::~JsonStreamParser() {} - - -absl::Status JsonStreamParser::Parse(absl::string_view json) { - absl::string_view chunk = json; - // If we have leftovers from a previous chunk, append the new chunk to it - // and create a new absl::string_view pointing at the string's data. This - // could be large but we rely on the chunks to be small, assuming they are - // fragments of a Cord. - if (!leftover_.empty()) { - // Don't point chunk to leftover_ because leftover_ will be updated in - // ParseChunk(chunk). - chunk_storage_.swap(leftover_); - absl::StrAppend(&chunk_storage_, json); - chunk = absl::string_view(chunk_storage_); - } - - // Find the structurally valid UTF8 prefix and parse only that. - int n = internal::UTF8SpnStructurallyValid(chunk); - if (n > 0) { - absl::Status status = ParseChunk(chunk.substr(0, n)); - - // Any leftover characters are stashed in leftover_ for later parsing when - // there is more data available. - absl::StrAppend(&leftover_, chunk.substr(n)); - return status; - } else { - leftover_.assign(chunk.data(), chunk.size()); - return absl::Status(); - } -} - -absl::Status JsonStreamParser::FinishParse() { - // If we do not expect anything and there is nothing left to parse we're all - // done. - if (stack_.empty() && leftover_.empty()) { - return absl::Status(); - } - - // Lifetime needs to last until RunParser returns, so keep this variable - // outside of the coerce_to_utf8 block. - std::unique_ptr scratch; - - bool is_valid_utf8 = internal::IsStructurallyValidUTF8(leftover_); - if (coerce_to_utf8_ && !is_valid_utf8) { - scratch.reset(new std::string); - scratch->reserve(leftover_.size() * utf8_replacement_character_.size()); - ReplaceInvalidCodePoints(leftover_, utf8_replacement_character_, - scratch.get()); - p_ = json_ = *scratch; - } else { - p_ = json_ = leftover_; - if (!is_valid_utf8) { - return ReportFailure("Encountered non UTF-8 code points.", - ParseErrorType::NON_UTF_8); - } - } - - // Parse the remainder in finishing mode, which reports errors for things like - // unterminated strings or unknown tokens that would normally be retried. - finishing_ = true; - absl::Status result = RunParser(); - if (result.ok()) { - SkipWhitespace(); - if (!p_.empty()) { - result = - ReportFailure("Parsing terminated before end of input.", - ParseErrorType::PARSING_TERMINATED_BEFORE_END_OF_INPUT); - } - } - return result; -} - -absl::Status JsonStreamParser::ParseChunk(absl::string_view chunk) { - // Do not do any work if the chunk is empty. - if (chunk.empty()) return absl::Status(); - - p_ = json_ = chunk; - - finishing_ = false; - absl::Status result = RunParser(); - if (!result.ok()) return result; - - SkipWhitespace(); - if (p_.empty()) { - // If we parsed everything we had, clear the leftover. - leftover_.clear(); - } else { - // If we do not expect anything i.e. stack is empty, and we have non-empty - // string left to parse, we report an error. - if (stack_.empty()) { - return ReportFailure( - "Parsing terminated before end of input.", - ParseErrorType::PARSING_TERMINATED_BEFORE_END_OF_INPUT); - } - // If we expect future data i.e. stack is non-empty, and we have some - // unparsed data left, we save it for later parse. - leftover_ = std::string(p_); - } - return absl::Status(); -} - -bool JsonStreamParser::IsInputAllWhiteSpaces(TokenType type) { - // Conclude the whole input is full of white spaces by: - // - it is at the finishing stage - // - we have run out of the input data - // - haven't seen non-whitespace char so far - if (finishing_ && p_.empty() && type == UNKNOWN && !seen_non_whitespace_) { - return true; - } - return false; -} - -absl::Status JsonStreamParser::RunParser() { - while (!stack_.empty()) { - ParseType type = stack_.top(); - TokenType t = (string_open_ == 0) ? GetNextTokenType() : BEGIN_STRING; - stack_.pop(); - absl::Status result; - switch (type) { - case VALUE: - if (allow_no_root_element_ && IsInputAllWhiteSpaces(t)) { - return absl::Status(); - } - result = ParseValue(t); - break; - - case OBJ_MID: - result = ParseObjectMid(t); - break; - - case ENTRY: - result = ParseEntry(t); - break; - - case ENTRY_MID: - result = ParseEntryMid(t); - break; - - case ARRAY_VALUE: - result = ParseArrayValue(t); - break; - - case ARRAY_MID: - result = ParseArrayMid(t); - break; - - default: - result = - absl::InternalError(absl::StrCat("Unknown parse type: ", type)); - break; - } - if (!result.ok()) { - // If we were cancelled, save our state and try again later. - if (!finishing_ && absl::IsCancelled(result)) { - stack_.push(type); - // If we have a key we still need to render, make sure to save off the - // contents in our own storage. - if (!key_.empty() && key_storage_.empty()) { - absl::StrAppend(&key_storage_, key_); - key_ = absl::string_view(key_storage_); - } - result = absl::Status(); - } - return result; - } - } - return absl::Status(); -} - -absl::Status JsonStreamParser::ParseValue(TokenType type) { - switch (type) { - case BEGIN_OBJECT: - return HandleBeginObject(); - case BEGIN_ARRAY: - return HandleBeginArray(); - case BEGIN_STRING: - return ParseString(); - case BEGIN_NUMBER: - return ParseNumber(); - case BEGIN_TRUE: - return ParseTrue(); - case BEGIN_FALSE: - return ParseFalse(); - case BEGIN_NULL: - return ParseNull(); - case UNKNOWN: - return ReportUnknown("Expected a value.", ParseErrorType::EXPECTED_VALUE); - default: { - // Special case for having been cut off while parsing, wait for more data. - // This handles things like 'fals' being at the end of the string, we - // don't know if the next char would be e, completing it, or something - // else, making it invalid. - if (!finishing_ && p_.length() < kKeywordFalse.length()) { - return absl::CancelledError(""); - } - - if (allow_empty_null_ && IsEmptyNullAllowed(type)) { - return ParseEmptyNull(); - } - return ReportFailure("Unexpected token.", - ParseErrorType::UNEXPECTED_TOKEN); - } - } -} - -absl::Status JsonStreamParser::ParseString() { - absl::Status result = ParseStringHelper(); - if (result.ok()) { - ow_->RenderString(key_, parsed_); - key_ = absl::string_view(); - parsed_ = absl::string_view(); - parsed_storage_.clear(); - } - return result; -} - -absl::Status JsonStreamParser::ParseStringHelper() { - // If we haven't seen the start quote, grab it and remember it for later. - if (string_open_ == 0) { - string_open_ = *p_.data(); - GOOGLE_DCHECK(string_open_ == '\"' || string_open_ == '\''); - Advance(); - } - // Track where we last copied data from so we can minimize copying. - const char* last = p_.data(); - while (!p_.empty()) { - const char* data = p_.data(); - if (*data == '\\') { - // We're about to handle an escape, copy all bytes from last to data. - if (last < data) { - parsed_storage_.append(last, data - last); - } - // If we ran out of string after the \, cancel or report an error - // depending on if we expect more data later. - if (p_.length() == 1) { - if (!finishing_) { - return absl::CancelledError(""); - } - return ReportFailure("Closing quote expected in string.", - ParseErrorType::EXPECTED_CLOSING_QUOTE); - } - // Parse a unicode escape if we found \u in the string. - if (data[1] == 'u') { - absl::Status result = ParseUnicodeEscape(); - if (!result.ok()) { - return result; - } - // Move last pointer past the unicode escape and continue. - last = p_.data(); - continue; - } - // Handle the standard set of backslash-escaped characters. - switch (data[1]) { - case 'b': - parsed_storage_.push_back('\b'); - break; - case 'f': - parsed_storage_.push_back('\f'); - break; - case 'n': - parsed_storage_.push_back('\n'); - break; - case 'r': - parsed_storage_.push_back('\r'); - break; - case 't': - parsed_storage_.push_back('\t'); - break; - case 'v': - parsed_storage_.push_back('\v'); - break; - default: - parsed_storage_.push_back(data[1]); - } - // We handled two characters, so advance past them and continue. - p_.remove_prefix(2); - last = p_.data(); - continue; - } - // If we found the closing quote note it, advance past it, and return. - if (*data == string_open_) { - // If we didn't copy anything, reuse the input buffer. - if (parsed_storage_.empty()) { - parsed_ = absl::string_view(last, data - last); - } else { - if (last < data) { - parsed_storage_.append(last, data - last); - } - parsed_ = absl::string_view(parsed_storage_); - } - // Clear the quote char so next time we try to parse a string we'll - // start fresh. - string_open_ = 0; - Advance(); - return absl::Status(); - } - // Normal character, just advance past it. - Advance(); - } - // If we ran out of characters, copy over what we have so far. - if (last < p_.data()) { - parsed_storage_.append(last, p_.data() - last); - } - // If we didn't find the closing quote but we expect more data, cancel for now - if (!finishing_) { - return absl::CancelledError(""); - } - // End of string reached without a closing quote, report an error. - string_open_ = 0; - return ReportFailure("Closing quote expected in string.", - ParseErrorType::EXPECTED_CLOSING_QUOTE); -} - -// Converts a unicode escaped character to a decimal value stored in a char32 -// for use in UTF8 encoding utility. We assume that str begins with \uhhhh and -// convert that from the hex number to a decimal value. -// -// There are some security exploits with UTF-8 that we should be careful of: -// - http://www.unicode.org/reports/tr36/#UTF-8_Exploit -// - http://sites/intl-eng/design-guide/core-application -absl::Status JsonStreamParser::ParseUnicodeEscape() { - if (p_.length() < kUnicodeEscapedLength) { - if (!finishing_) { - return absl::CancelledError(""); - } - return ReportFailure("Illegal hex string.", - ParseErrorType::ILLEGAL_HEX_STRING); - } - GOOGLE_DCHECK_EQ('\\', p_.data()[0]); - GOOGLE_DCHECK_EQ('u', p_.data()[1]); - uint32_t code = 0; - for (int i = 2; i < kUnicodeEscapedLength; ++i) { - if (!isxdigit(p_.data()[i])) { - return ReportFailure("Invalid escape sequence.", - ParseErrorType::INVALID_ESCAPE_SEQUENCE); - } - code = (code << 4) + hex_digit_to_int(p_.data()[i]); - } - if (code >= JsonEscaping::kMinHighSurrogate && - code <= JsonEscaping::kMaxHighSurrogate) { - if (p_.length() < 2 * kUnicodeEscapedLength) { - if (!finishing_) { - return absl::CancelledError(""); - } - if (!coerce_to_utf8_) { - return ReportFailure("Missing low surrogate.", - ParseErrorType::MISSING_LOW_SURROGATE); - } - } else if (p_.data()[kUnicodeEscapedLength] == '\\' && - p_.data()[kUnicodeEscapedLength + 1] == 'u') { - uint32_t low_code = 0; - for (int i = kUnicodeEscapedLength + 2; i < 2 * kUnicodeEscapedLength; - ++i) { - if (!isxdigit(p_.data()[i])) { - return ReportFailure("Invalid escape sequence.", - ParseErrorType::INVALID_ESCAPE_SEQUENCE); - } - low_code = (low_code << 4) + hex_digit_to_int(p_.data()[i]); - } - if (low_code >= JsonEscaping::kMinLowSurrogate && - low_code <= JsonEscaping::kMaxLowSurrogate) { - // Convert UTF-16 surrogate pair to 21-bit Unicode codepoint. - code = (((code & 0x3FF) << 10) | (low_code & 0x3FF)) + - JsonEscaping::kMinSupplementaryCodePoint; - // Advance past the first code unit escape. - p_.remove_prefix(kUnicodeEscapedLength); - } else if (!coerce_to_utf8_) { - return ReportFailure("Invalid low surrogate.", - ParseErrorType::INVALID_LOW_SURROGATE); - } - } else if (!coerce_to_utf8_) { - return ReportFailure("Missing low surrogate.", - ParseErrorType::MISSING_LOW_SURROGATE); - } - } - if (!coerce_to_utf8_ && !IsValidCodePoint(code)) { - return ReportFailure("Invalid unicode code point.", - ParseErrorType::INVALID_UNICODE); - } - char buf[UTFmax]; - int len = EncodeAsUTF8Char(code, buf); - // Advance past the [final] code unit escape. - p_.remove_prefix(kUnicodeEscapedLength); - parsed_storage_.append(buf, len); - return absl::Status(); -} - -absl::Status JsonStreamParser::ParseNumber() { - NumberResult number; - absl::Status result = ParseNumberHelper(&number); - if (result.ok()) { - switch (number.type) { - case NumberResult::DOUBLE: - ow_->RenderDouble(key_, number.double_val); - key_ = absl::string_view(); - break; - - case NumberResult::INT: - ow_->RenderInt64(key_, number.int_val); - key_ = absl::string_view(); - break; - - case NumberResult::UINT: - ow_->RenderUint64(key_, number.uint_val); - key_ = absl::string_view(); - break; - - default: - return ReportFailure("Unable to parse number.", - ParseErrorType::UNABLE_TO_PARSE_NUMBER); - } - } - return result; -} - -absl::Status JsonStreamParser::ParseDoubleHelper(const std::string& number, - NumberResult* result) { - if (!safe_strtod(number, &result->double_val)) { - return ReportFailure("Unable to parse number.", - ParseErrorType::UNABLE_TO_PARSE_NUMBER); - } - if (!loose_float_number_conversion_ && !std::isfinite(result->double_val)) { - return ReportFailure("Number exceeds the range of double.", - ParseErrorType::NUMBER_EXCEEDS_RANGE_DOUBLE); - } - result->type = NumberResult::DOUBLE; - return absl::Status(); -} - -absl::Status JsonStreamParser::ParseNumberHelper(NumberResult* result) { - const char* data = p_.data(); - int length = p_.length(); - - // Look for the first non-numeric character, or the end of the string. - int index = 0; - bool floating = false; - bool negative = data[index] == '-'; - // Find the first character that cannot be part of the number. Along the way - // detect if the number needs to be parsed as a double. - // Note that this restricts numbers to the JSON specification, so for example - // we do not support hex or octal notations. - for (; index < length; ++index) { - char c = data[index]; - if (isdigit(c)) continue; - if (c == '.' || c == 'e' || c == 'E') { - floating = true; - continue; - } - if (c == '+' || c == '-' || c == 'x') continue; - // Not a valid number character, break out. - break; - } - - // If the entire input is a valid number, and we may have more content in the - // future, we abort for now and resume when we know more. - if (index == length && !finishing_) { - return absl::CancelledError(""); - } - - // Create a string containing just the number, so we can use safe_strtoX - std::string number = std::string(p_.substr(0, index)); - - // Floating point number, parse as a double. - if (floating) { - absl::Status status = ParseDoubleHelper(number, result); - if (status.ok()) { - p_.remove_prefix(index); - } - return status; - } - - // Positive non-floating point number, parse as a uint64_t. - if (!negative) { - // Octal/Hex numbers are not valid JSON values. - if (number.length() >= 2 && number[0] == '0') { - return ReportFailure( - "Octal/hex numbers are not valid JSON values.", - ParseErrorType::OCTAL_OR_HEX_ARE_NOT_VALID_JSON_VALUES); - } - if (safe_strtou64(number, &result->uint_val)) { - result->type = NumberResult::UINT; - p_.remove_prefix(index); - return absl::Status(); - } else { - // If the value is too large, parse it as double. - absl::Status status = ParseDoubleHelper(number, result); - if (status.ok()) { - p_.remove_prefix(index); - } - return status; - } - } - - // Octal/Hex numbers are not valid JSON values. - if (number.length() >= 3 && number[1] == '0') { - return ReportFailure( - "Octal/hex numbers are not valid JSON values.", - ParseErrorType::OCTAL_OR_HEX_ARE_NOT_VALID_JSON_VALUES); - } - // Negative non-floating point number, parse as an int64_t. - if (safe_strto64(number, &result->int_val)) { - result->type = NumberResult::INT; - p_.remove_prefix(index); - return absl::Status(); - } else { - // If the value is too large, parse it as double. - absl::Status status = ParseDoubleHelper(number, result); - if (status.ok()) { - p_.remove_prefix(index); - } - return status; - } -} - -absl::Status JsonStreamParser::HandleBeginObject() { - GOOGLE_DCHECK_EQ('{', *p_.data()); - Advance(); - ow_->StartObject(key_); - auto status = IncrementRecursionDepth(key_); - if (!status.ok()) { - return status; - } - key_ = absl::string_view(); - stack_.push(ENTRY); - return absl::Status(); -} - -absl::Status JsonStreamParser::ParseObjectMid(TokenType type) { - if (type == UNKNOWN) { - return ReportUnknown("Expected , or } after key:value pair.", - ParseErrorType::EXPECTED_COMMA_OR_BRACES); - } - - // Object is complete, advance past the comma and render the EndObject. - if (type == END_OBJECT) { - Advance(); - ow_->EndObject(); - --recursion_depth_; - return absl::Status(); - } - // Found a comma, advance past it and get ready for an entry. - if (type == VALUE_SEPARATOR) { - Advance(); - stack_.push(ENTRY); - return absl::Status(); - } - // Illegal token after key:value pair. - return ReportFailure("Expected , or } after key:value pair.", - ParseErrorType::EXPECTED_COMMA_OR_BRACES); -} - -absl::Status JsonStreamParser::ParseEntry(TokenType type) { - if (type == UNKNOWN) { - return ReportUnknown("Expected an object key or }.", - ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES); - } - - // Close the object and return. This allows for trailing commas. - if (type == END_OBJECT) { - ow_->EndObject(); - Advance(); - --recursion_depth_; - return absl::Status(); - } - - absl::Status result; - if (type == BEGIN_STRING) { - // Key is a string (standard JSON), parse it and store the string. - result = ParseStringHelper(); - if (result.ok()) { - key_storage_.clear(); - if (!parsed_storage_.empty()) { - parsed_storage_.swap(key_storage_); - key_ = absl::string_view(key_storage_); - } else { - key_ = parsed_; - } - parsed_ = absl::string_view(); - } - } else if (type == BEGIN_KEY) { - // Key is a bare key (back compat), create a absl::string_view pointing to - // it. - result = ParseKey(); - } else if (type == BEGIN_NULL || type == BEGIN_TRUE || type == BEGIN_FALSE) { - // Key may be a bare key that begins with a reserved word. - result = ParseKey(); - if (result.ok() && (key_ == kKeywordNull || key_ == kKeywordTrue || - key_ == kKeywordFalse)) { - result = ReportFailure("Expected an object key or }.", - ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES); - } - } else { - // Unknown key type, report an error. - result = ReportFailure("Expected an object key or }.", - ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES); - } - // On success we next expect an entry mid ':' then an object mid ',' or '}' - if (result.ok()) { - stack_.push(OBJ_MID); - stack_.push(ENTRY_MID); - } - return result; -} - -absl::Status JsonStreamParser::ParseEntryMid(TokenType type) { - if (type == UNKNOWN) { - return ReportUnknown("Expected : between key:value pair.", - ParseErrorType::EXPECTED_COLON); - } - if (type == ENTRY_SEPARATOR) { - Advance(); - stack_.push(VALUE); - return absl::Status(); - } - return ReportFailure("Expected : between key:value pair.", - ParseErrorType::EXPECTED_COLON); -} - -absl::Status JsonStreamParser::HandleBeginArray() { - GOOGLE_DCHECK_EQ('[', *p_.data()); - Advance(); - ow_->StartList(key_); - key_ = absl::string_view(); - stack_.push(ARRAY_VALUE); - return absl::Status(); -} - -absl::Status JsonStreamParser::ParseArrayValue(TokenType type) { - if (type == UNKNOWN) { - return ReportUnknown("Expected a value or ] within an array.", - ParseErrorType::EXPECTED_VALUE_OR_BRACKET); - } - - if (type == END_ARRAY) { - ow_->EndList(); - Advance(); - return absl::Status(); - } - - // The ParseValue call may push something onto the stack so we need to make - // sure an ARRAY_MID is after it, so we push it on now. Also, the parsing of - // empty-null array value is relying on this ARRAY_MID token. - stack_.push(ARRAY_MID); - absl::Status result = ParseValue(type); - if (absl::IsCancelled(result)) { - // If we were cancelled, pop back off the ARRAY_MID so we don't try to - // push it on again when we try over. - stack_.pop(); - } - return result; -} - -absl::Status JsonStreamParser::ParseArrayMid(TokenType type) { - if (type == UNKNOWN) { - return ReportUnknown("Expected , or ] after array value.", - ParseErrorType::EXPECTED_COMMA_OR_BRACKET); - } - - if (type == END_ARRAY) { - ow_->EndList(); - Advance(); - return absl::Status(); - } - - // Found a comma, advance past it and expect an array value next. - if (type == VALUE_SEPARATOR) { - Advance(); - stack_.push(ARRAY_VALUE); - return absl::Status(); - } - // Illegal token after array value. - return ReportFailure("Expected , or ] after array value.", - ParseErrorType::EXPECTED_COMMA_OR_BRACKET); -} - -absl::Status JsonStreamParser::ParseTrue() { - ow_->RenderBool(key_, true); - key_ = absl::string_view(); - p_.remove_prefix(kKeywordTrue.length()); - return absl::Status(); -} - -absl::Status JsonStreamParser::ParseFalse() { - ow_->RenderBool(key_, false); - key_ = absl::string_view(); - p_.remove_prefix(kKeywordFalse.length()); - return absl::Status(); -} - -absl::Status JsonStreamParser::ParseNull() { - ow_->RenderNull(key_); - key_ = absl::string_view(); - p_.remove_prefix(kKeywordNull.length()); - return absl::Status(); -} - -absl::Status JsonStreamParser::ParseEmptyNull() { - ow_->RenderNull(key_); - key_ = absl::string_view(); - return absl::Status(); -} - -bool JsonStreamParser::IsEmptyNullAllowed(TokenType type) { - if (stack_.empty()) return false; - return (stack_.top() == ARRAY_MID && type == VALUE_SEPARATOR) || - stack_.top() == OBJ_MID; -} - -absl::Status JsonStreamParser::ReportFailure(absl::string_view message, - ParseErrorType parse_code) { - (void)parse_code; // Parameter is used in Google-internal code. - static const int kContextLength = 20; - const char* p_start = p_.data(); - const char* json_start = json_.data(); - const char* begin = std::max(p_start - kContextLength, json_start); - const char* end = - std::min(p_start + kContextLength, json_start + json_.size()); - absl::string_view segment(begin, end - begin); - std::string location(p_start - begin, ' '); - location.push_back('^'); - auto status = absl::InvalidArgumentError( - absl::StrCat(message, "\n", segment, "\n", location)); - return status; -} - -absl::Status JsonStreamParser::ReportUnknown(absl::string_view message, - ParseErrorType parse_code) { - // If we aren't finishing the parse, cancel parsing and try later. - if (!finishing_) { - return absl::CancelledError(""); - } - if (p_.empty()) { - return ReportFailure(absl::StrCat("Unexpected end of string. ", message), - parse_code); - } - return ReportFailure(message, parse_code); -} - -absl::Status JsonStreamParser::IncrementRecursionDepth( - absl::string_view key) const { - if (++recursion_depth_ > max_recursion_depth_) { - return absl::InvalidArgumentError(absl::StrCat( - "Message too deep. Max recursion depth reached for key '", key, "'")); - } - return absl::Status(); -} - -void JsonStreamParser::SkipWhitespace() { - while (!p_.empty() && absl::ascii_isspace(*p_.data())) { - Advance(); - } - if (!p_.empty() && !absl::ascii_isspace(*p_.data())) { - seen_non_whitespace_ = true; - } -} - -void JsonStreamParser::Advance() { - // Advance by moving one UTF8 character while making sure we don't go beyond - // the length of the string. - p_.remove_prefix(std::min( - p_.length(), UTF8FirstLetterNumBytes(p_.data(), p_.length()))); -} - -absl::Status JsonStreamParser::ParseKey() { - absl::string_view original = p_; - - if (allow_permissive_key_naming_) { - if (!ConsumeKeyPermissive(&p_, &key_)) { - return ReportFailure("Invalid key or variable name.", - ParseErrorType::INVALID_KEY_OR_VARIABLE_NAME); - } - } else { - if (!ConsumeKey(&p_, &key_)) { - return ReportFailure("Invalid key or variable name.", - ParseErrorType::INVALID_KEY_OR_VARIABLE_NAME); - } - } - - // If we consumed everything but expect more data, reset p_ and cancel since - // we can't know if the key was complete or not. - if (!finishing_ && p_.empty()) { - p_ = original; - return absl::CancelledError(""); - } - // Since we aren't using the key storage, clear it out. - key_storage_.clear(); - return absl::Status(); -} - -JsonStreamParser::TokenType JsonStreamParser::GetNextTokenType() { - SkipWhitespace(); - - int size = p_.size(); - if (size == 0) { - // If we ran out of data, report unknown and we'll place the previous parse - // type onto the stack and try again when we have more data. - return UNKNOWN; - } - // TODO(sven): Split this method based on context since different contexts - // support different tokens. Would slightly speed up processing? - const char* data = p_.data(); - absl::string_view data_view = absl::string_view(data, size); - if (*data == '\"' || *data == '\'') return BEGIN_STRING; - if (*data == '-' || ('0' <= *data && *data <= '9')) { - return BEGIN_NUMBER; - } - if (size >= kKeywordTrue.length() && - absl::StartsWith(data_view, kKeywordTrue)) { - return BEGIN_TRUE; - } - if (size >= kKeywordFalse.length() && - absl::StartsWith(data_view, kKeywordFalse)) { - return BEGIN_FALSE; - } - if (size >= kKeywordNull.length() && - absl::StartsWith(data_view, kKeywordNull)) { - return BEGIN_NULL; - } - if (*data == '{') return BEGIN_OBJECT; - if (*data == '}') return END_OBJECT; - if (*data == '[') return BEGIN_ARRAY; - if (*data == ']') return END_ARRAY; - if (*data == ':') return ENTRY_SEPARATOR; - if (*data == ',') return VALUE_SEPARATOR; - if (MatchKey(p_)) { - return BEGIN_KEY; - } - - // We don't know that we necessarily have an invalid token here, just that we - // can't parse what we have so far. So we don't report an error and just - // return UNKNOWN so we can try again later when we have more data, or if we - // finish and we have leftovers. - return UNKNOWN; -} - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/util/internal/json_stream_parser.h b/src/google/protobuf/util/internal/json_stream_parser.h deleted file mode 100644 index 9f30a057aa..0000000000 --- a/src/google/protobuf/util/internal/json_stream_parser.h +++ /dev/null @@ -1,352 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_STREAM_PARSER_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_STREAM_PARSER_H__ - -#include -#include -#include - -#include "google/protobuf/stubs/common.h" -#include "absl/status/status.h" -#include "google/protobuf/port.h" -#include "absl/strings/string_view.h" - - -// Must be included last. -#include "google/protobuf/port_def.inc" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - - -class ObjectWriter; - -// A JSON parser that can parse a stream of JSON chunks rather than needing the -// entire JSON string up front. It is a modified version of the parser in -// //net/proto/json/json-parser.h that has been changed in the following ways: -// - Changed from recursion to an explicit stack to allow resumption -// - Added support for int64 and uint64 numbers -// - Removed support for octal and decimal escapes -// - Removed support for numeric keys -// - Removed support for functions (javascript) -// - Removed some lax-comma support (but kept trailing comma support) -// - Writes directly to an ObjectWriter rather than using subclassing -// -// Here is an example usage: -// JsonStreamParser parser(ow_.get()); -// util::Status result = parser.Parse(chunk1); -// result.Update(parser.Parse(chunk2)); -// result.Update(parser.FinishParse()); -// GOOGLE_DCHECK(result.ok()) << "Failed to parse JSON"; -// -// This parser is thread-compatible as long as only one thread is calling a -// Parse() method at a time. -class PROTOBUF_EXPORT JsonStreamParser { - public: - // Creates a JsonStreamParser that will write to the given ObjectWriter. - explicit JsonStreamParser(ObjectWriter* ow); - JsonStreamParser() = delete; - JsonStreamParser(const JsonStreamParser&) = delete; - JsonStreamParser& operator=(const JsonStreamParser&) = delete; - virtual ~JsonStreamParser(); - - // Parses a UTF-8 encoded JSON string from an absl::string_view. If the - // returned status is non-ok, the status might contain a payload - // ParseErrorType with type_url kParseErrorTypeUrl and a payload containing - // string snippet of the error with type_url kParseErrorSnippetUrl. - absl::Status Parse(absl::string_view json); - - - // Finish parsing the JSON string. If the returned status is non-ok, the - // status might contain a payload ParseErrorType with type_url - // kParseErrorTypeUrl and a payload containing string snippet of the error - // with type_url kParseErrorSnippetUrl. - absl::Status FinishParse(); - - - // Sets the max recursion depth of JSON message to be deserialized. JSON - // messages over this depth will fail to be deserialized. - // Default value is 100. - void set_max_recursion_depth(int max_depth) { - max_recursion_depth_ = max_depth; - } - - // Denotes the cause of error. - enum ParseErrorType { - UNKNOWN_PARSE_ERROR, - OCTAL_OR_HEX_ARE_NOT_VALID_JSON_VALUES, - EXPECTED_COLON, - EXPECTED_COMMA_OR_BRACKET, - EXPECTED_VALUE, - EXPECTED_COMMA_OR_BRACES, - EXPECTED_OBJECT_KEY_OR_BRACES, - EXPECTED_VALUE_OR_BRACKET, - INVALID_KEY_OR_VARIABLE_NAME, - NON_UTF_8, - PARSING_TERMINATED_BEFORE_END_OF_INPUT, - UNEXPECTED_TOKEN, - EXPECTED_CLOSING_QUOTE, - ILLEGAL_HEX_STRING, - INVALID_ESCAPE_SEQUENCE, - MISSING_LOW_SURROGATE, - INVALID_LOW_SURROGATE, - INVALID_UNICODE, - UNABLE_TO_PARSE_NUMBER, - NUMBER_EXCEEDS_RANGE_DOUBLE - }; - - private: - friend class JsonStreamParserTest; - // Return the current recursion depth. - int recursion_depth() { return recursion_depth_; } - - enum TokenType { - BEGIN_STRING, // " or ' - BEGIN_NUMBER, // - or digit - BEGIN_TRUE, // true - BEGIN_FALSE, // false - BEGIN_NULL, // null - BEGIN_OBJECT, // { - END_OBJECT, // } - BEGIN_ARRAY, // [ - END_ARRAY, // ] - ENTRY_SEPARATOR, // : - VALUE_SEPARATOR, // , - BEGIN_KEY, // letter, _, $ or digit. Must begin with non-digit - UNKNOWN // Unknown token or we ran out of the stream. - }; - - enum ParseType { - VALUE, // Expects a {, [, true, false, null, string or number - OBJ_MID, // Expects a ',' or } - ENTRY, // Expects a key or } - ENTRY_MID, // Expects a : - ARRAY_VALUE, // Expects a value or ] - ARRAY_MID // Expects a ',' or ] - }; - - // Holds the result of parsing a number - struct NumberResult { - enum Type { DOUBLE, INT, UINT }; - Type type; - union { - double double_val; - int64_t int_val; - uint64_t uint_val; - }; - }; - - // Parses a single chunk of JSON, returning an error if the JSON was invalid. - absl::Status ParseChunk(absl::string_view chunk); - - // Runs the parser based on stack_ and p_, until the stack is empty or p_ runs - // out of data. If we unexpectedly run out of p_ we push the latest back onto - // the stack and return. - absl::Status RunParser(); - - // Parses a value from p_ and writes it to ow_. - // A value may be an object, array, true, false, null, string or number. - absl::Status ParseValue(TokenType type); - - // Parses a string and writes it out to the ow_. - absl::Status ParseString(); - - // Parses a string, storing the result in parsed_. - absl::Status ParseStringHelper(); - - // This function parses unicode escape sequences in strings. It returns an - // error when there's a parsing error, either the size is not the expected - // size or a character is not a hex digit. When it returns str will contain - // what has been successfully parsed so far. - absl::Status ParseUnicodeEscape(); - - // Expects p_ to point to a JSON number, writes the number to the writer using - // the appropriate Render method based on the type of number. - absl::Status ParseNumber(); - - // Parse a number into a NumberResult, reporting an error if no number could - // be parsed. This method will try to parse into a uint64, int64, or double - // based on whether the number was positive or negative or had a decimal - // component. - absl::Status ParseNumberHelper(NumberResult* result); - - // Parse a number as double into a NumberResult. - absl::Status ParseDoubleHelper(const std::string& number, - NumberResult* result); - - // Handles a { during parsing of a value. - absl::Status HandleBeginObject(); - - // Parses from the ENTRY state. - absl::Status ParseEntry(TokenType type); - - // Parses from the ENTRY_MID state. - absl::Status ParseEntryMid(TokenType type); - - // Parses from the OBJ_MID state. - absl::Status ParseObjectMid(TokenType type); - - // Handles a [ during parsing of a value. - absl::Status HandleBeginArray(); - - // Parses from the ARRAY_VALUE state. - absl::Status ParseArrayValue(TokenType type); - - // Parses from the ARRAY_MID state. - absl::Status ParseArrayMid(TokenType type); - - // Expects p_ to point to an unquoted literal - absl::Status ParseTrue(); - absl::Status ParseFalse(); - absl::Status ParseNull(); - absl::Status ParseEmptyNull(); - - // Whether an empty-null is allowed in the current state. - bool IsEmptyNullAllowed(TokenType type); - - // Whether the whole input is all whitespaces. - bool IsInputAllWhiteSpaces(TokenType type); - - // Report a failure as a util::Status. - absl::Status ReportFailure(absl::string_view message, - ParseErrorType parse_code); - - // Report a failure due to an UNKNOWN token type. We check if we hit the - // end of the stream and if we're finishing or not to detect what type of - // status to return in this case. - absl::Status ReportUnknown(absl::string_view message, - ParseErrorType parse_code); - - // Helper function to check recursion depth and increment it. It will return - // OkStatus() if the current depth is allowed. Otherwise an error is returned. - // key is used for error reporting. - absl::Status IncrementRecursionDepth(absl::string_view key) const; - - // Advance p_ past all whitespace or until the end of the string. - void SkipWhitespace(); - - // Advance p_ one UTF-8 character - void Advance(); - - // Expects p_ to point to the beginning of a key. - absl::Status ParseKey(); - - // Return the type of the next token at p_. - TokenType GetNextTokenType(); - - // The object writer to write parse events to. - ObjectWriter* ow_; - - // The stack of parsing we still need to do. When the stack runs empty we will - // have parsed a single value from the root (e.g. an object or list). - std::stack stack_; - - // Contains any leftover text from a previous chunk that we weren't able to - // fully parse, for example the start of a key or number. - std::string leftover_; - - // The current chunk of JSON being parsed. Primarily used for providing - // context during error reporting. - absl::string_view json_; - - // A pointer within the current JSON being parsed, used to track location. - absl::string_view p_; - - // Stores the last key read, as we separate parsing of keys and values. - absl::string_view key_; - - // Storage for key_ if we need to keep ownership, for example between chunks - // or if the key was unescaped from a JSON string. - std::string key_storage_; - - // True during the FinishParse() call, so we know that any errors are fatal. - // For example an unterminated string will normally result in cancelling and - // trying during the next chunk, but during FinishParse() it is an error. - bool finishing_; - - // Whether non whitespace tokens have been seen during parsing. - // It is used to handle the case of a pure whitespace stream input. - bool seen_non_whitespace_; - - // The JsonStreamParser requires a root element by default and it will raise - // error if the root element is missing. If `allow_no_root_element_` is true, - // the JsonStreamParser can also handle this case. - bool allow_no_root_element_; - - // String we parsed during a call to ParseStringHelper(). - absl::string_view parsed_; - - // Storage for the string we parsed. This may be empty if the string was able - // to be parsed directly from the input. - std::string parsed_storage_; - - // The character that opened the string, either ' or ". - // A value of 0 indicates that string parsing is not in process. - char string_open_; - - // Storage for the chunk that are being parsed in ParseChunk(). - std::string chunk_storage_; - - // Whether to allow non UTF-8 encoded input and replace invalid code points. - bool coerce_to_utf8_; - - // Replacement character for invalid UTF-8 code points. - std::string utf8_replacement_character_; - - // Whether allows empty string represented null array value or object entry - // value. - bool allow_empty_null_; - - // Whether unquoted object keys can contain embedded non-alphanumeric - // characters when this is unambiguous for parsing. - bool allow_permissive_key_naming_; - - // Whether allows out-of-range floating point numbers or reject them. - bool loose_float_number_conversion_; - - // Tracks current recursion depth. - mutable int recursion_depth_; - - // Maximum allowed recursion depth. - int max_recursion_depth_; -}; - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google - -#include "google/protobuf/port_undef.inc" - -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_STREAM_PARSER_H__ diff --git a/src/google/protobuf/util/internal/json_stream_parser_test.cc b/src/google/protobuf/util/internal/json_stream_parser_test.cc deleted file mode 100644 index 9d3fd4c958..0000000000 --- a/src/google/protobuf/util/internal/json_stream_parser_test.cc +++ /dev/null @@ -1,980 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google/protobuf/util/internal/json_stream_parser.h" - -#include - -#include "google/protobuf/stubs/logging.h" -#include "google/protobuf/stubs/common.h" -#include "google/protobuf/util/internal/expecting_objectwriter.h" -#include -#include "absl/status/status.h" -#include "absl/strings/str_cat.h" -#include "absl/time/time.h" -#include "google/protobuf/util/internal/object_writer.h" - - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -using ParseErrorType = - ::google::protobuf::util::converter::JsonStreamParser::ParseErrorType; - - -// Tests for the JSON Stream Parser. These tests are intended to be -// comprehensive and cover the following: -// -// Positive tests: -// - true, false, null -// - empty object or array. -// - negative and positive double and int, unsigned int -// - single and double quoted strings -// - string key, unquoted key, numeric key -// - array containing array, object, value -// - object containing array, object, value -// - unicode handling in strings -// - ascii escaping (\b, \f, \n, \r, \t, \v) -// - trailing commas -// -// Negative tests: -// - illegal literals -// - mismatched quotes failure on strings -// - unterminated string failure -// - unexpected end of string failure -// - mismatched object and array closing -// - Failure to close array or object -// - numbers too large -// - invalid unicode escapes. -// - invalid unicode sequences. -// - numbers as keys -// -// For each test we split the input string on every possible character to ensure -// the parser is able to handle arbitrarily split input for all cases. We also -// do a final test of the entire test case one character at a time. -// -// It is verified that expected calls to the mocked objects are in sequence. -class JsonStreamParserTest : public ::testing::Test { - protected: - JsonStreamParserTest() : mock_(), ow_(&mock_) {} - ~JsonStreamParserTest() override {} - - absl::Status RunTest(absl::string_view json, int split, - std::function setup) { - JsonStreamParser parser(&mock_); - setup(&parser); - - // Special case for split == length, test parsing one character at a time. - if (split == json.length()) { - GOOGLE_LOG(INFO) << "Testing split every char: " << json; - for (int i = 0; i < json.length(); ++i) { - absl::string_view single = json.substr(i, 1); - absl::Status result = parser.Parse(single); - if (!result.ok()) { - return result; - } - } - return parser.FinishParse(); - } - - // Normal case, split at the split point and parse two substrings. - absl::string_view first = json.substr(0, split); - absl::string_view rest = json.substr(split); - GOOGLE_LOG(INFO) << "Testing split: " << first << "><" << rest; - absl::Status result = parser.Parse(first); - if (result.ok()) { - result = parser.Parse(rest); - if (result.ok()) { - result = parser.FinishParse(); - } - } - if (result.ok()) { - EXPECT_EQ(parser.recursion_depth(), 0); - } - return result; - } - - void DoTest( - absl::string_view json, int split, - std::function setup = [](JsonStreamParser* p) { - }) { - absl::Status result = RunTest(json, split, setup); - if (!result.ok()) { - GOOGLE_LOG(WARNING) << result; - } - EXPECT_TRUE(result.ok()); - } - - void DoErrorTest( - absl::string_view json, int split, absl::string_view error_prefix, - std::function setup = [](JsonStreamParser* p) { - }) { - absl::Status result = RunTest(json, split, setup); - EXPECT_TRUE(absl::IsInvalidArgument(result)); - absl::string_view error_message(result.message()); - EXPECT_EQ(error_prefix, error_message.substr(0, error_prefix.size())); - } - - void DoErrorTest( - absl::string_view json, int split, absl::string_view error_prefix, - ParseErrorType expected_parse_error_type, - std::function setup = [](JsonStreamParser* p) { - }) { - absl::Status result = RunTest(json, split, setup); - EXPECT_TRUE(absl::IsInvalidArgument(result)); - absl::string_view error_message(result.message()); - EXPECT_EQ(error_prefix, error_message.substr(0, error_prefix.size())); - } - - -#ifndef _MSC_VER - // TODO(xiaofeng): We have to disable InSequence check for MSVC because it - // causes stack overflow due to its use of a linked list that is destructed - // recursively. - ::testing::InSequence in_sequence_; -#endif // !_MSC_VER - MockObjectWriter mock_; - ExpectingObjectWriter ow_; -}; - - -// Positive tests - -// - true, false, null -TEST_F(JsonStreamParserTest, SimpleTrue) { - absl::string_view str = "true"; - for (int i = 0; i <= str.length(); ++i) { - ow_.RenderBool("", true); - DoTest(str, i); - } -} - -TEST_F(JsonStreamParserTest, SimpleFalse) { - absl::string_view str = "false"; - for (int i = 0; i <= str.length(); ++i) { - ow_.RenderBool("", false); - DoTest(str, i); - } -} - -TEST_F(JsonStreamParserTest, SimpleNull) { - absl::string_view str = "null"; - for (int i = 0; i <= str.length(); ++i) { - ow_.RenderNull(""); - DoTest(str, i); - } -} - -// - empty object and array. -TEST_F(JsonStreamParserTest, EmptyObject) { - absl::string_view str = "{}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject("")->EndObject(); - DoTest(str, i); - } -} - -TEST_F(JsonStreamParserTest, EmptyList) { - absl::string_view str = "[]"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartList("")->EndList(); - DoTest(str, i); - } -} - -// - negative and positive double and int, unsigned int -TEST_F(JsonStreamParserTest, SimpleDouble) { - absl::string_view str = "42.5"; - for (int i = 0; i <= str.length(); ++i) { - ow_.RenderDouble("", 42.5); - DoTest(str, i); - } -} - -TEST_F(JsonStreamParserTest, ScientificDouble) { - absl::string_view str = "1.2345e-10"; - for (int i = 0; i < str.length(); ++i) { - ow_.RenderDouble("", 1.2345e-10); - DoTest(str, i); - } -} - -TEST_F(JsonStreamParserTest, SimpleNegativeDouble) { - absl::string_view str = "-1045.235"; - for (int i = 0; i <= str.length(); ++i) { - ow_.RenderDouble("", -1045.235); - DoTest(str, i); - } -} - -TEST_F(JsonStreamParserTest, SimpleInt) { - absl::string_view str = "123456"; - for (int i = 0; i <= str.length(); ++i) { - ow_.RenderUint64("", 123456); - DoTest(str, i); - } -} - -TEST_F(JsonStreamParserTest, SimpleNegativeInt) { - absl::string_view str = "-79497823553162765"; - for (int i = 0; i <= str.length(); ++i) { - ow_.RenderInt64("", int64_t{-79497823553162765}); - DoTest(str, i); - } -} - -TEST_F(JsonStreamParserTest, SimpleUnsignedInt) { - absl::string_view str = "11779497823553162765"; - for (int i = 0; i <= str.length(); ++i) { - ow_.RenderUint64("", uint64_t{11779497823553162765u}); - DoTest(str, i); - } -} - -TEST_F(JsonStreamParserTest, OctalNumberIsInvalid) { - absl::string_view str = "01234"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values.", - ParseErrorType::OCTAL_OR_HEX_ARE_NOT_VALID_JSON_VALUES); - } - str = "-01234"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values.", - ParseErrorType::OCTAL_OR_HEX_ARE_NOT_VALID_JSON_VALUES); - } -} - -TEST_F(JsonStreamParserTest, HexNumberIsInvalid) { - absl::string_view str = "0x1234"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values.", - ParseErrorType::OCTAL_OR_HEX_ARE_NOT_VALID_JSON_VALUES); - } - str = "-0x1234"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values.", - ParseErrorType::OCTAL_OR_HEX_ARE_NOT_VALID_JSON_VALUES); - } - str = "12x34"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Unable to parse number.", - ParseErrorType::UNABLE_TO_PARSE_NUMBER); - } -} - -// - single and double quoted strings -TEST_F(JsonStreamParserTest, EmptyDoubleQuotedString) { - absl::string_view str = "\"\""; - for (int i = 0; i <= str.length(); ++i) { - ow_.RenderString("", ""); - DoTest(str, i); - } -} - -TEST_F(JsonStreamParserTest, EmptySingleQuotedString) { - absl::string_view str = "''"; - for (int i = 0; i <= str.length(); ++i) { - ow_.RenderString("", ""); - DoTest(str, i); - } -} - -TEST_F(JsonStreamParserTest, SimpleDoubleQuotedString) { - absl::string_view str = "\"Some String\""; - for (int i = 0; i <= str.length(); ++i) { - ow_.RenderString("", "Some String"); - DoTest(str, i); - } -} - -TEST_F(JsonStreamParserTest, SimpleSingleQuotedString) { - absl::string_view str = "'Another String'"; - for (int i = 0; i <= str.length(); ++i) { - ow_.RenderString("", "Another String"); - DoTest(str, i); - } -} - -// - string key, unquoted key, numeric key -TEST_F(JsonStreamParserTest, ObjectKeyTypes) { - absl::string_view str = - "{'s': true, \"d\": false, key: null, snake_key: [], camelKey: {}}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject("") - ->RenderBool("s", true) - ->RenderBool("d", false) - ->RenderNull("key") - ->StartList("snake_key") - ->EndList() - ->StartObject("camelKey") - ->EndObject() - ->EndObject(); - DoTest(str, i); - } -} - -TEST_F(JsonStreamParserTest, UnquotedObjectKeyWithReservedPrefxes) { - absl::string_view str = "{ nullkey: \"a\", truekey: \"b\", falsekey: \"c\"}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject("") - ->RenderString("nullkey", "a") - ->RenderString("truekey", "b") - ->RenderString("falsekey", "c") - ->EndObject(); - DoTest(str, i); - } -} - -TEST_F(JsonStreamParserTest, UnquotedObjectKeyWithReservedKeyword) { - absl::string_view str = "{ null: \"a\", true: \"b\", false: \"c\"}"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Expected an object key or }.", - ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES); - } -} - -TEST_F(JsonStreamParserTest, UnquotedObjectKeyWithEmbeddedNonAlphanumeric) { - absl::string_view str = "{ foo-bar-baz: \"a\"}"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Expected : between key:value pair.", - ParseErrorType::EXPECTED_COLON); - } -} - - -// - array containing primitive values (true, false, null, num, string) -TEST_F(JsonStreamParserTest, ArrayPrimitiveValues) { - absl::string_view str = "[true, false, null, 'one', \"two\"]"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartList("") - ->RenderBool("", true) - ->RenderBool("", false) - ->RenderNull("") - ->RenderString("", "one") - ->RenderString("", "two") - ->EndList(); - DoTest(str, i); - } -} - -// - array containing array, object -TEST_F(JsonStreamParserTest, ArrayComplexValues) { - absl::string_view str = - "[[22, -127, 45.3, -1056.4, 11779497823553162765], {'key': true}]"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartList("") - ->StartList("") - ->RenderUint64("", 22) - ->RenderInt64("", -127) - ->RenderDouble("", 45.3) - ->RenderDouble("", -1056.4) - ->RenderUint64("", uint64_t{11779497823553162765u}) - ->EndList() - ->StartObject("") - ->RenderBool("key", true) - ->EndObject() - ->EndList(); - DoTest(str, i); - } -} - - -// - object containing array, object, value (true, false, null, num, string) -TEST_F(JsonStreamParserTest, ObjectValues) { - absl::string_view str = - "{t: true, f: false, n: null, s: 'a string', d: \"another string\", pi: " - "22, ni: -127, pd: 45.3, nd: -1056.4, pl: 11779497823553162765, l: [[]], " - "o: {'key': true}}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject("") - ->RenderBool("t", true) - ->RenderBool("f", false) - ->RenderNull("n") - ->RenderString("s", "a string") - ->RenderString("d", "another string") - ->RenderUint64("pi", 22) - ->RenderInt64("ni", -127) - ->RenderDouble("pd", 45.3) - ->RenderDouble("nd", -1056.4) - ->RenderUint64("pl", uint64_t{11779497823553162765u}) - ->StartList("l") - ->StartList("") - ->EndList() - ->EndList() - ->StartObject("o") - ->RenderBool("key", true) - ->EndObject() - ->EndObject(); - DoTest(str, i); - } -} - - -TEST_F(JsonStreamParserTest, RejectNonUtf8WhenNotCoerced) { - absl::string_view json = "{\"address\":\xFF\"חרושת 23, רעננה, ישראל\"}"; - for (int i = 0; i <= json.length(); ++i) { - DoErrorTest(json, i, "Encountered non UTF-8 code points.", - ParseErrorType::NON_UTF_8); - } - json = "{\"address\": \"חרושת 23,\xFFרעננה, ישראל\"}"; - for (int i = 0; i <= json.length(); ++i) { - DoErrorTest(json, i, "Encountered non UTF-8 code points.", - ParseErrorType::NON_UTF_8); - } - DoErrorTest("\xFF{}", 0, "Encountered non UTF-8 code points.", - ParseErrorType::NON_UTF_8); -} - -// - unicode handling in strings -TEST_F(JsonStreamParserTest, UnicodeEscaping) { - absl::string_view str = "[\"\\u0639\\u0631\\u0628\\u0649\"]"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartList("") - ->RenderString("", "\xD8\xB9\xD8\xB1\xD8\xA8\xD9\x89") - ->EndList(); - DoTest(str, i); - } -} - -// - unicode UTF-16 surrogate pair handling in strings -TEST_F(JsonStreamParserTest, UnicodeSurrogatePairEscaping) { - absl::string_view str = - "[\"\\u0bee\\ud800\\uddf1\\uD80C\\uDDA4\\uD83d\\udC1D\\uD83C\\uDF6F\"]"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartList("") - ->RenderString("", - "\xE0\xAF\xAE\xF0\x90\x87\xB1\xF0\x93\x86\xA4\xF0" - "\x9F\x90\x9D\xF0\x9F\x8D\xAF") - ->EndList(); - DoTest(str, i); - } -} - - -TEST_F(JsonStreamParserTest, UnicodeEscapingInvalidCodePointWhenNotCoerced) { - // A low surrogate alone. - absl::string_view str = "[\"\\ude36\"]"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Invalid unicode code point.", - ParseErrorType::INVALID_UNICODE); - } -} - -TEST_F(JsonStreamParserTest, UnicodeEscapingMissingLowSurrogateWhenNotCoerced) { - // A high surrogate alone. - absl::string_view str = "[\"\\ud83d\"]"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Missing low surrogate.", - ParseErrorType::MISSING_LOW_SURROGATE); - } - // A high surrogate with some trailing characters. - str = "[\"\\ud83d|ude36\"]"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Missing low surrogate.", - ParseErrorType::MISSING_LOW_SURROGATE); - } - // A high surrogate with half a low surrogate. - str = "[\"\\ud83d\\ude--\"]"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Invalid escape sequence.", - ParseErrorType::INVALID_ESCAPE_SEQUENCE); - } - // Two high surrogates. - str = "[\"\\ud83d\\ud83d\"]"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Invalid low surrogate.", - ParseErrorType::INVALID_LOW_SURROGATE); - } -} - -// - ascii escaping (\b, \f, \n, \r, \t, \v) -TEST_F(JsonStreamParserTest, AsciiEscaping) { - absl::string_view str = - "[\"\\b\", \"\\ning\", \"test\\f\", \"\\r\\t\", \"test\\\\\\ving\"]"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartList("") - ->RenderString("", "\b") - ->RenderString("", "\ning") - ->RenderString("", "test\f") - ->RenderString("", "\r\t") - ->RenderString("", "test\\\ving") - ->EndList(); - DoTest(str, i); - } -} - -// - trailing commas, we support a single trailing comma but no internal commas. -TEST_F(JsonStreamParserTest, TrailingCommas) { - absl::string_view str = "[['a',true,], {b: null,},]"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartList("") - ->StartList("") - ->RenderString("", "a") - ->RenderBool("", true) - ->EndList() - ->StartObject("") - ->RenderNull("b") - ->EndObject() - ->EndList(); - DoTest(str, i); - } -} - -// Negative tests - -// illegal literals -TEST_F(JsonStreamParserTest, ExtraTextAfterTrue) { - absl::string_view str = "truee"; - for (int i = 0; i <= str.length(); ++i) { - ow_.RenderBool("", true); - DoErrorTest(str, i, "Parsing terminated before end of input.", - ParseErrorType::PARSING_TERMINATED_BEFORE_END_OF_INPUT); - } -} - -TEST_F(JsonStreamParserTest, InvalidNumberDashOnly) { - absl::string_view str = "-"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Unable to parse number.", - ParseErrorType::UNABLE_TO_PARSE_NUMBER); - } -} - -TEST_F(JsonStreamParserTest, InvalidNumberDashName) { - absl::string_view str = "-foo"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Unable to parse number.", - ParseErrorType::UNABLE_TO_PARSE_NUMBER); - } -} - -TEST_F(JsonStreamParserTest, InvalidLiteralInArray) { - absl::string_view str = "[nule]"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartList(""); - DoErrorTest(str, i, "Unexpected token.", ParseErrorType::UNEXPECTED_TOKEN); - } -} - -TEST_F(JsonStreamParserTest, InvalidLiteralInObject) { - absl::string_view str = "{123false}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject(""); - DoErrorTest(str, i, "Expected an object key or }.", - ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES); - } -} - -// mismatched quotes failure on strings -TEST_F(JsonStreamParserTest, MismatchedSingleQuotedLiteral) { - absl::string_view str = "'Some str\""; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Closing quote expected in string.", - ParseErrorType::EXPECTED_CLOSING_QUOTE); - } -} - -TEST_F(JsonStreamParserTest, MismatchedDoubleQuotedLiteral) { - absl::string_view str = "\"Another string that ends poorly!'"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Closing quote expected in string.", - ParseErrorType::EXPECTED_CLOSING_QUOTE); - } -} - -// unterminated strings -TEST_F(JsonStreamParserTest, UnterminatedLiteralString) { - absl::string_view str = "\"Forgot the rest of i"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Closing quote expected in string.", - ParseErrorType::EXPECTED_CLOSING_QUOTE); - } -} - -TEST_F(JsonStreamParserTest, UnterminatedStringEscape) { - absl::string_view str = "\"Forgot the rest of \\"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Closing quote expected in string.", - ParseErrorType::EXPECTED_CLOSING_QUOTE); - } -} - -TEST_F(JsonStreamParserTest, UnterminatedStringInArray) { - absl::string_view str = "[\"Forgot to close the string]"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartList(""); - DoErrorTest(str, i, "Closing quote expected in string.", - ParseErrorType::EXPECTED_CLOSING_QUOTE); - } -} - -TEST_F(JsonStreamParserTest, UnterminatedStringInObject) { - absl::string_view str = "{f: \"Forgot to close the string}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject(""); - DoErrorTest(str, i, "Closing quote expected in string.", - ParseErrorType::EXPECTED_CLOSING_QUOTE); - } -} - -TEST_F(JsonStreamParserTest, UnterminatedObject) { - absl::string_view str = "{"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject(""); - DoErrorTest(str, i, "Unexpected end of string.", - ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES); - } -} - - -// mismatched object and array closing -TEST_F(JsonStreamParserTest, MismatchedCloseObject) { - absl::string_view str = "{'key': true]"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject("")->RenderBool("key", true); - DoErrorTest(str, i, "Expected , or } after key:value pair.", - ParseErrorType::EXPECTED_COMMA_OR_BRACES); - } -} - -TEST_F(JsonStreamParserTest, MismatchedCloseArray) { - absl::string_view str = "[true, null}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartList("")->RenderBool("", true)->RenderNull(""); - DoErrorTest(str, i, "Expected , or ] after array value.", - ParseErrorType::EXPECTED_COMMA_OR_BRACKET); - } -} - -// Invalid object keys. -TEST_F(JsonStreamParserTest, InvalidNumericObjectKey) { - absl::string_view str = "{42: true}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject(""); - DoErrorTest(str, i, "Expected an object key or }.", - ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES); - } -} - -TEST_F(JsonStreamParserTest, InvalidLiteralObjectInObject) { - absl::string_view str = "{{bob: true}}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject(""); - DoErrorTest(str, i, "Expected an object key or }.", - ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES); - } -} - -TEST_F(JsonStreamParserTest, InvalidLiteralArrayInObject) { - absl::string_view str = "{[null]}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject(""); - DoErrorTest(str, i, "Expected an object key or }.", - ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES); - } -} - -TEST_F(JsonStreamParserTest, InvalidLiteralValueInObject) { - absl::string_view str = "{false}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject(""); - DoErrorTest(str, i, "Expected an object key or }.", - ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES); - } -} - -TEST_F(JsonStreamParserTest, MissingColonAfterStringInObject) { - absl::string_view str = "{\"key\"}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject(""); - DoErrorTest(str, i, "Expected : between key:value pair.", - ParseErrorType::EXPECTED_COLON); - } -} - -TEST_F(JsonStreamParserTest, MissingColonAfterKeyInObject) { - absl::string_view str = "{key}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject(""); - DoErrorTest(str, i, "Expected : between key:value pair.", - ParseErrorType::EXPECTED_COLON); - } -} - -TEST_F(JsonStreamParserTest, EndOfTextAfterKeyInObject) { - absl::string_view str = "{key"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject(""); - DoErrorTest(str, i, "Unexpected end of string.", - ParseErrorType::EXPECTED_COLON); - } -} - -TEST_F(JsonStreamParserTest, MissingValueAfterColonInObject) { - absl::string_view str = "{key:}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject(""); - DoErrorTest(str, i, "Unexpected token.", ParseErrorType::UNEXPECTED_TOKEN); - } -} - -TEST_F(JsonStreamParserTest, MissingCommaBetweenObjectEntries) { - absl::string_view str = "{key:20 'hello': true}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject("")->RenderUint64("key", 20); - DoErrorTest(str, i, "Expected , or } after key:value pair.", - ParseErrorType::EXPECTED_COMMA_OR_BRACES); - } -} - -TEST_F(JsonStreamParserTest, InvalidLiteralAsObjectKey) { - absl::string_view str = "{false: 20}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject(""); - DoErrorTest(str, i, "Expected an object key or }.", - ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES); - } -} - -TEST_F(JsonStreamParserTest, ExtraCharactersAfterObject) { - absl::string_view str = "{}}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject("")->EndObject(); - DoErrorTest(str, i, "Parsing terminated before end of input.", - ParseErrorType::PARSING_TERMINATED_BEFORE_END_OF_INPUT); - } -} - -TEST_F(JsonStreamParserTest, PositiveNumberTooBigIsDouble) { - absl::string_view str = "18446744073709551616"; // 2^64 - for (int i = 0; i <= str.length(); ++i) { - ow_.RenderDouble("", 18446744073709552000.0); - DoTest(str, i); - } -} - -TEST_F(JsonStreamParserTest, NegativeNumberTooBigIsDouble) { - absl::string_view str = "-18446744073709551616"; - for (int i = 0; i <= str.length(); ++i) { - ow_.RenderDouble("", -18446744073709551616.0); - DoTest(str, i); - } -} - -TEST_F(JsonStreamParserTest, DoubleTooBig) { - absl::string_view str = "[1.89769e+308]"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartList(""); - DoErrorTest(str, i, "Number exceeds the range of double.", - ParseErrorType::NUMBER_EXCEEDS_RANGE_DOUBLE); - } - str = "[-1.89769e+308]"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartList(""); - DoErrorTest(str, i, "Number exceeds the range of double.", - ParseErrorType::NUMBER_EXCEEDS_RANGE_DOUBLE); - } -} - - -// invalid bare backslash. -TEST_F(JsonStreamParserTest, UnfinishedEscape) { - absl::string_view str = "\"\\"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Closing quote expected in string.", - ParseErrorType::EXPECTED_CLOSING_QUOTE); - } -} - -// invalid bare backslash u. -TEST_F(JsonStreamParserTest, UnfinishedUnicodeEscape) { - absl::string_view str = "\"\\u"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Illegal hex string.", - ParseErrorType::ILLEGAL_HEX_STRING); - } -} - -// invalid unicode sequence. -TEST_F(JsonStreamParserTest, UnicodeEscapeCutOff) { - absl::string_view str = "\"\\u12"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Illegal hex string.", - ParseErrorType::ILLEGAL_HEX_STRING); - } -} - -// invalid unicode sequence (valid in modern EcmaScript but not in JSON). -TEST_F(JsonStreamParserTest, BracketedUnicodeEscape) { - absl::string_view str = "\"\\u{1f36f}\""; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Invalid escape sequence.", - ParseErrorType::INVALID_ESCAPE_SEQUENCE); - } -} - - -TEST_F(JsonStreamParserTest, UnicodeEscapeInvalidCharacters) { - absl::string_view str = "\"\\u12$4hello"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Invalid escape sequence.", - ParseErrorType::INVALID_ESCAPE_SEQUENCE); - } -} - -// invalid unicode sequence in low half surrogate: g is not a hex digit. -TEST_F(JsonStreamParserTest, UnicodeEscapeLowHalfSurrogateInvalidCharacters) { - absl::string_view str = "\"\\ud800\\udcfg\""; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Invalid escape sequence.", - ParseErrorType::INVALID_ESCAPE_SEQUENCE); - } -} - -// Extra commas with an object or array. -TEST_F(JsonStreamParserTest, ExtraCommaInObject) { - absl::string_view str = "{'k1': true,,'k2': false}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject("")->RenderBool("k1", true); - DoErrorTest(str, i, "Expected an object key or }.", - ParseErrorType::EXPECTED_OBJECT_KEY_OR_BRACES); - } -} - -TEST_F(JsonStreamParserTest, ExtraCommaInArray) { - absl::string_view str = "[true,,false}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartList("")->RenderBool("", true); - DoErrorTest(str, i, "Unexpected token.", ParseErrorType::UNEXPECTED_TOKEN); - } -} - -// Extra text beyond end of value. -TEST_F(JsonStreamParserTest, ExtraTextAfterLiteral) { - absl::string_view str = "'hello', 'world'"; - for (int i = 0; i <= str.length(); ++i) { - ow_.RenderString("", "hello"); - DoErrorTest(str, i, "Parsing terminated before end of input.", - ParseErrorType::PARSING_TERMINATED_BEFORE_END_OF_INPUT); - } -} - -TEST_F(JsonStreamParserTest, ExtraTextAfterObject) { - absl::string_view str = "{'key': true} 'oops'"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject("")->RenderBool("key", true)->EndObject(); - DoErrorTest(str, i, "Parsing terminated before end of input.", - ParseErrorType::PARSING_TERMINATED_BEFORE_END_OF_INPUT); - } -} - -TEST_F(JsonStreamParserTest, ExtraTextAfterArray) { - absl::string_view str = "[null] 'oops'"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartList("")->RenderNull("")->EndList(); - DoErrorTest(str, i, "Parsing terminated before end of input.", - ParseErrorType::PARSING_TERMINATED_BEFORE_END_OF_INPUT); - } -} - -// Random unknown text in the value. -TEST_F(JsonStreamParserTest, UnknownCharactersAsValue) { - absl::string_view str = "*"; - for (int i = 0; i <= str.length(); ++i) { - DoErrorTest(str, i, "Expected a value.", ParseErrorType::EXPECTED_VALUE); - } -} - -TEST_F(JsonStreamParserTest, UnknownCharactersInArray) { - absl::string_view str = "[*]"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartList(""); - DoErrorTest(str, i, "Expected a value or ] within an array.", - ParseErrorType::EXPECTED_VALUE_OR_BRACKET); - } -} - -TEST_F(JsonStreamParserTest, UnknownCharactersInObject) { - absl::string_view str = "{'key': *}"; - for (int i = 0; i <= str.length(); ++i) { - ow_.StartObject(""); - DoErrorTest(str, i, "Expected a value.", ParseErrorType::EXPECTED_VALUE); - } -} - -TEST_F(JsonStreamParserTest, DeepNestJsonNotExceedLimit) { - int count = 99; - std::string str; - for (int i = 0; i < count; ++i) { - absl::StrAppend(&str, "{'a':"); - } - absl::StrAppend(&str, "{'nest64':'v1', 'nest64': false, 'nest64': ['v2']}"); - for (int i = 0; i < count; ++i) { - absl::StrAppend(&str, "}"); - } - ow_.StartObject(""); - for (int i = 0; i < count; ++i) { - ow_.StartObject("a"); - } - ow_.RenderString("nest64", "v1") - ->RenderBool("nest64", false) - ->StartList("nest64") - ->RenderString("", "v2") - ->EndList(); - for (int i = 0; i < count; ++i) { - ow_.EndObject(); - } - ow_.EndObject(); - DoTest(str, 0); -} - -TEST_F(JsonStreamParserTest, DeepNestJsonExceedLimit) { - int count = 98; - std::string str; - for (int i = 0; i < count; ++i) { - absl::StrAppend(&str, "{'a':"); - } - // Supports trailing commas. - absl::StrAppend(&str, - "{'nest11' : [{'nest12' : null,},]," - "'nest21' : {'nest22' : {'nest23' : false}}}"); - for (int i = 0; i < count; ++i) { - absl::StrAppend(&str, "}"); - } - DoErrorTest(str, 0, - "Message too deep. Max recursion depth reached for key 'nest22'"); -} - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/util/internal/object_location_tracker.h b/src/google/protobuf/util/internal/object_location_tracker.h deleted file mode 100644 index c5a8f27b75..0000000000 --- a/src/google/protobuf/util/internal/object_location_tracker.h +++ /dev/null @@ -1,63 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_LOCATION_TRACKER_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_LOCATION_TRACKER_H__ - -#include - -#include "google/protobuf/port.h" -#include "google/protobuf/util/internal/location_tracker.h" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -// An empty concrete implementation of LocationTrackerInterface. -class ObjectLocationTracker : public LocationTrackerInterface { - public: - // Creates an empty location tracker. - ObjectLocationTracker() {} - ObjectLocationTracker(const ObjectLocationTracker&) = delete; - ObjectLocationTracker& operator=(const ObjectLocationTracker&) = delete; - - ~ObjectLocationTracker() override {} - - // Returns empty because nothing is tracked. - std::string ToString() const override { return ""; } -}; - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google - -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_LOCATION_TRACKER_H__ diff --git a/src/google/protobuf/util/internal/object_writer.cc b/src/google/protobuf/util/internal/object_writer.cc deleted file mode 100644 index c03c19593e..0000000000 --- a/src/google/protobuf/util/internal/object_writer.cc +++ /dev/null @@ -1,93 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google/protobuf/util/internal/object_writer.h" - -#include "google/protobuf/util/internal/datapiece.h" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -// static -void ObjectWriter::RenderDataPieceTo(const DataPiece& data, - absl::string_view name, ObjectWriter* ow) { - switch (data.type()) { - case DataPiece::TYPE_INT32: { - ow->RenderInt32(name, data.ToInt32().value()); - break; - } - case DataPiece::TYPE_INT64: { - ow->RenderInt64(name, data.ToInt64().value()); - break; - } - case DataPiece::TYPE_UINT32: { - ow->RenderUint32(name, data.ToUint32().value()); - break; - } - case DataPiece::TYPE_UINT64: { - ow->RenderUint64(name, data.ToUint64().value()); - break; - } - case DataPiece::TYPE_DOUBLE: { - ow->RenderDouble(name, data.ToDouble().value()); - break; - } - case DataPiece::TYPE_FLOAT: { - ow->RenderFloat(name, data.ToFloat().value()); - break; - } - case DataPiece::TYPE_BOOL: { - ow->RenderBool(name, data.ToBool().value()); - break; - } - case DataPiece::TYPE_STRING: { - ow->RenderString(name, data.ToString().value()); - break; - } - case DataPiece::TYPE_BYTES: { - ow->RenderBytes(name, data.ToBytes().value()); - break; - } - case DataPiece::TYPE_NULL: { - ow->RenderNull(name); - break; - } - default: - break; - } -} - - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/util/internal/object_writer.h b/src/google/protobuf/util/internal/object_writer.h deleted file mode 100644 index a91c628f10..0000000000 --- a/src/google/protobuf/util/internal/object_writer.h +++ /dev/null @@ -1,152 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_WRITER_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_WRITER_H__ - -#include - -#include "google/protobuf/stubs/common.h" -#include "google/protobuf/port.h" -#include "absl/strings/string_view.h" - -// Must be included last. -#include "google/protobuf/port_def.inc" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - - -class DataPiece; - -// An ObjectWriter is an interface for writing a stream of events -// representing objects and collections. Implementation of this -// interface can be used to write an object stream to an in-memory -// structure, protobufs, JSON, XML, or any other output format -// desired. The ObjectSource interface is typically used as the -// source of an object stream. -// -// See JsonObjectWriter for a sample implementation of ObjectWriter -// and its use. -// -// Derived classes could be thread-unsafe. -// -// TODO(xinb): seems like a prime candidate to apply the RAII paradigm -// and get rid the need to call EndXXX(). -class PROTOBUF_EXPORT ObjectWriter { - public: - ObjectWriter(const ObjectWriter&) = delete; - ObjectWriter& operator=(const ObjectWriter&) = delete; - virtual ~ObjectWriter() {} - - // Starts an object. If the name is empty, the object will not be named. - virtual ObjectWriter* StartObject(absl::string_view name) = 0; - - // Ends an object. - virtual ObjectWriter* EndObject() = 0; - - // Starts a list. If the name is empty, the list will not be named. - virtual ObjectWriter* StartList(absl::string_view name) = 0; - - // Ends a list. - virtual ObjectWriter* EndList() = 0; - - // Renders a boolean value. - virtual ObjectWriter* RenderBool(absl::string_view name, bool value) = 0; - - // Renders an 32-bit integer value. - virtual ObjectWriter* RenderInt32(absl::string_view name, int32_t value) = 0; - - // Renders an 32-bit unsigned integer value. - virtual ObjectWriter* RenderUint32(absl::string_view name, - uint32_t value) = 0; - - // Renders a 64-bit integer value. - virtual ObjectWriter* RenderInt64(absl::string_view name, int64_t value) = 0; - - // Renders an 64-bit unsigned integer value. - virtual ObjectWriter* RenderUint64(absl::string_view name, - uint64_t value) = 0; - - - // Renders a double value. - virtual ObjectWriter* RenderDouble(absl::string_view name, double value) = 0; - // Renders a float value. - virtual ObjectWriter* RenderFloat(absl::string_view name, float value) = 0; - - // Renders a string value. - virtual ObjectWriter* RenderString(absl::string_view name, - absl::string_view value) = 0; - - // Renders a bytes value. - virtual ObjectWriter* RenderBytes(absl::string_view name, - absl::string_view value) = 0; - - // Renders a Null value. - virtual ObjectWriter* RenderNull(absl::string_view name) = 0; - - - // Renders a DataPiece object to a ObjectWriter. - static void RenderDataPieceTo(const DataPiece& data, absl::string_view name, - ObjectWriter* ow); - - - // Indicates whether this ObjectWriter has completed writing the root message, - // usually this means writing of one complete object. Subclasses must override - // this behavior appropriately. - virtual bool done() { return false; } - - void set_use_strict_base64_decoding(bool value) { - use_strict_base64_decoding_ = value; - } - - bool use_strict_base64_decoding() const { - return use_strict_base64_decoding_; - } - - protected: - ObjectWriter() : use_strict_base64_decoding_(true) {} - - private: - // If set to true, we use the stricter version of base64 decoding for byte - // fields by making sure decoded version encodes back to the original string. - bool use_strict_base64_decoding_; -}; - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google - -#include "google/protobuf/port_undef.inc" - -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_WRITER_H__ diff --git a/src/google/protobuf/util/internal/proto_writer.cc b/src/google/protobuf/util/internal/proto_writer.cc deleted file mode 100644 index 792443701f..0000000000 --- a/src/google/protobuf/util/internal/proto_writer.cc +++ /dev/null @@ -1,827 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google/protobuf/util/internal/proto_writer.h" - -#include -#include -#include -#include - -#include "google/protobuf/wire_format_lite.h" -#include "absl/base/call_once.h" -#include "absl/status/statusor.h" -#include "absl/strings/ascii.h" -#include "absl/strings/escaping.h" -#include "absl/strings/str_cat.h" -#include "absl/time/clock.h" -#include "absl/time/time.h" -#include "google/protobuf/util/internal/constants.h" -#include "google/protobuf/util/internal/field_mask_utility.h" -#include "google/protobuf/util/internal/object_location_tracker.h" -#include "google/protobuf/util/internal/utility.h" - - -// Must be included last. -#include "google/protobuf/port_def.inc" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -using io::CodedOutputStream; -using ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite; - -ProtoWriter::ProtoWriter(TypeResolver* type_resolver, - const google::protobuf::Type& type, - strings::ByteSink* output, ErrorListener* listener) - : master_type_(type), - typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), - own_typeinfo_(true), - done_(false), - ignore_unknown_fields_(false), - ignore_unknown_enum_values_(false), - use_lower_camel_for_enums_(false), - case_insensitive_enum_parsing_(true), - use_json_name_in_missing_fields_(false), - element_(nullptr), - size_insert_(), - output_(output), - adapter_(&buffer_), - stream_(new CodedOutputStream(&adapter_)), - listener_(listener), - invalid_depth_(0), - tracker_(new ObjectLocationTracker()) {} - -ProtoWriter::ProtoWriter(const TypeInfo* typeinfo, - const google::protobuf::Type& type, - strings::ByteSink* output, ErrorListener* listener) - : master_type_(type), - typeinfo_(typeinfo), - own_typeinfo_(false), - done_(false), - ignore_unknown_fields_(false), - ignore_unknown_enum_values_(false), - use_lower_camel_for_enums_(false), - case_insensitive_enum_parsing_(true), - use_json_name_in_missing_fields_(false), - element_(nullptr), - size_insert_(), - output_(output), - adapter_(&buffer_), - stream_(new CodedOutputStream(&adapter_)), - listener_(listener), - invalid_depth_(0), - tracker_(new ObjectLocationTracker()) {} - -ProtoWriter::~ProtoWriter() { - if (own_typeinfo_) { - delete typeinfo_; - } - if (element_ == nullptr) return; - // Cleanup explicitly in order to avoid destructor stack overflow when input - // is deeply nested. - // Cast to BaseElement to avoid doing additional checks (like missing fields) - // during pop(). - std::unique_ptr element( - static_cast(element_.get())->pop()); - while (element != nullptr) { - element.reset(element->pop()); - } -} - -namespace { - -// Writes an INT32 field, including tag to the stream. -inline absl::Status WriteInt32(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - absl::StatusOr i32 = data.ToInt32(); - if (i32.ok()) { - WireFormatLite::WriteInt32(field_number, i32.value(), stream); - } - return i32.status(); -} - -// writes an SFIXED32 field, including tag, to the stream. -inline absl::Status WriteSFixed32(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - absl::StatusOr i32 = data.ToInt32(); - if (i32.ok()) { - WireFormatLite::WriteSFixed32(field_number, i32.value(), stream); - } - return i32.status(); -} - -// Writes an SINT32 field, including tag, to the stream. -inline absl::Status WriteSInt32(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - absl::StatusOr i32 = data.ToInt32(); - if (i32.ok()) { - WireFormatLite::WriteSInt32(field_number, i32.value(), stream); - } - return i32.status(); -} - -// Writes a FIXED32 field, including tag, to the stream. -inline absl::Status WriteFixed32(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - absl::StatusOr u32 = data.ToUint32(); - if (u32.ok()) { - WireFormatLite::WriteFixed32(field_number, u32.value(), stream); - } - return u32.status(); -} - -// Writes a UINT32 field, including tag, to the stream. -inline absl::Status WriteUInt32(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - absl::StatusOr u32 = data.ToUint32(); - if (u32.ok()) { - WireFormatLite::WriteUInt32(field_number, u32.value(), stream); - } - return u32.status(); -} - -// Writes an INT64 field, including tag, to the stream. -inline absl::Status WriteInt64(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - absl::StatusOr i64 = data.ToInt64(); - if (i64.ok()) { - WireFormatLite::WriteInt64(field_number, i64.value(), stream); - } - return i64.status(); -} - -// Writes an SFIXED64 field, including tag, to the stream. -inline absl::Status WriteSFixed64(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - absl::StatusOr i64 = data.ToInt64(); - if (i64.ok()) { - WireFormatLite::WriteSFixed64(field_number, i64.value(), stream); - } - return i64.status(); -} - -// Writes an SINT64 field, including tag, to the stream. -inline absl::Status WriteSInt64(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - absl::StatusOr i64 = data.ToInt64(); - if (i64.ok()) { - WireFormatLite::WriteSInt64(field_number, i64.value(), stream); - } - return i64.status(); -} - -// Writes a FIXED64 field, including tag, to the stream. -inline absl::Status WriteFixed64(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - absl::StatusOr u64 = data.ToUint64(); - if (u64.ok()) { - WireFormatLite::WriteFixed64(field_number, u64.value(), stream); - } - return u64.status(); -} - -// Writes a UINT64 field, including tag, to the stream. -inline absl::Status WriteUInt64(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - absl::StatusOr u64 = data.ToUint64(); - if (u64.ok()) { - WireFormatLite::WriteUInt64(field_number, u64.value(), stream); - } - return u64.status(); -} - -// Writes a DOUBLE field, including tag, to the stream. -inline absl::Status WriteDouble(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - absl::StatusOr d = data.ToDouble(); - if (d.ok()) { - WireFormatLite::WriteDouble(field_number, d.value(), stream); - } - return d.status(); -} - -// Writes a FLOAT field, including tag, to the stream. -inline absl::Status WriteFloat(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - absl::StatusOr f = data.ToFloat(); - if (f.ok()) { - WireFormatLite::WriteFloat(field_number, f.value(), stream); - } - return f.status(); -} - -// Writes a BOOL field, including tag, to the stream. -inline absl::Status WriteBool(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - absl::StatusOr b = data.ToBool(); - if (b.ok()) { - WireFormatLite::WriteBool(field_number, b.value(), stream); - } - return b.status(); -} - -// Writes a BYTES field, including tag, to the stream. -inline absl::Status WriteBytes(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - absl::StatusOr c = data.ToBytes(); - if (c.ok()) { - WireFormatLite::WriteBytes(field_number, c.value(), stream); - } - return c.status(); -} - -// Writes a STRING field, including tag, to the stream. -inline absl::Status WriteString(int field_number, const DataPiece& data, - CodedOutputStream* stream) { - absl::StatusOr s = data.ToString(); - if (s.ok()) { - WireFormatLite::WriteString(field_number, s.value(), stream); - } - return s.status(); -} - -// Given a google::protobuf::Type, returns the set of all required fields. -std::unordered_set GetRequiredFields( - const google::protobuf::Type& type) { - std::unordered_set required; - for (int i = 0; i < type.fields_size(); i++) { - const google::protobuf::Field& field = type.fields(i); - if (field.cardinality() == google::protobuf::Field::CARDINALITY_REQUIRED) { - required.insert(&field); - } - } - return required; -} - -} // namespace - -ProtoWriter::ProtoElement::ProtoElement(const TypeInfo* typeinfo, - const google::protobuf::Type& type, - ProtoWriter* enclosing) - : BaseElement(nullptr), - ow_(enclosing), - parent_field_(nullptr), - typeinfo_(typeinfo), - proto3_(type.syntax() == google::protobuf::SYNTAX_PROTO3), - type_(type), - size_index_(-1), - array_index_(-1), - // oneof_indices_ values are 1-indexed (0 means not present). - oneof_indices_(type.oneofs_size() + 1) { - if (!proto3_) { - required_fields_ = GetRequiredFields(type_); - } -} - -ProtoWriter::ProtoElement::ProtoElement(ProtoWriter::ProtoElement* parent, - const google::protobuf::Field* field, - const google::protobuf::Type& type, - bool is_list) - : BaseElement(parent), - ow_(this->parent()->ow_), - parent_field_(field), - typeinfo_(this->parent()->typeinfo_), - proto3_(type.syntax() == google::protobuf::SYNTAX_PROTO3), - type_(type), - size_index_(!is_list && - field->kind() == google::protobuf::Field::TYPE_MESSAGE - ? ow_->size_insert_.size() - : -1), - array_index_(is_list ? 0 : -1), - // oneof_indices_ values are 1-indexed (0 means not present). - oneof_indices_(type_.oneofs_size() + 1) { - if (!is_list) { - if (ow_->IsRepeated(*field)) { - // Update array_index_ if it is an explicit list. - if (this->parent()->array_index_ >= 0) this->parent()->array_index_++; - } else if (!proto3_) { - // For required fields tracking. - this->parent()->RegisterField(field); - } - - if (field->kind() == google::protobuf::Field::TYPE_MESSAGE) { - if (!proto3_) { - required_fields_ = GetRequiredFields(type_); - } - int start_pos = ow_->stream_->ByteCount(); - // length of serialized message is the final buffer position minus - // starting buffer position, plus length adjustments for size fields - // of any nested messages. We start with -start_pos here, so we only - // need to add the final buffer position to it at the end. - SizeInfo info = {start_pos, -start_pos}; - ow_->size_insert_.push_back(info); - } - } -} - -ProtoWriter::ProtoElement* ProtoWriter::ProtoElement::pop() { - if (!proto3_) { - // Calls the registered error listener for any required field(s) not yet - // seen. - for (std::unordered_set::iterator it = - required_fields_.begin(); - it != required_fields_.end(); ++it) { - ow_->MissingField(ow_->use_json_name_in_missing_fields_ - ? (*it)->json_name() - : (*it)->name()); - } - } - // Computes the total number of proto bytes used by a message, also adjusts - // the size of all parent messages by the length of this size field. - // If size_index_ < 0, this is not a message, so no size field is added. - if (size_index_ >= 0) { - // Add the final buffer position to compute the total length of this - // serialized message. The stored value (before this addition) already - // contains the total length of the size fields of all nested messages - // minus the initial buffer position. - ow_->size_insert_[size_index_].size += ow_->stream_->ByteCount(); - // Calculate the length required to serialize the size field of the - // message, and propagate this additional size information upward to - // all enclosing messages. - int size = ow_->size_insert_[size_index_].size; - int length = CodedOutputStream::VarintSize32(size); - for (ProtoElement* e = parent(); e != nullptr; e = e->parent()) { - // Only nested messages have size field, lists do not have size field. - if (e->size_index_ >= 0) { - ow_->size_insert_[e->size_index_].size += length; - } - } - } - return BaseElement::pop(); -} - -void ProtoWriter::ProtoElement::RegisterField( - const google::protobuf::Field* field) { - if (!required_fields_.empty() && - field->cardinality() == google::protobuf::Field::CARDINALITY_REQUIRED) { - required_fields_.erase(field); - } -} - -std::string ProtoWriter::ProtoElement::ToString() const { - std::string loc = ""; - - // first populate a stack with the nodes since we need to process them - // from root to leaf when generating the string location - const ProtoWriter::ProtoElement* now = this; - std::stack element_stack; - while (now->parent() != nullptr) { - element_stack.push(now); - now = now->parent(); - } - - // now pop each node from the stack and append to the location string - while (!element_stack.empty()) { - now = element_stack.top(); - element_stack.pop(); - - if (!ow_->IsRepeated(*(now->parent_field_)) || - now->parent()->parent_field_ != now->parent_field_) { - std::string name = now->parent_field_->name(); - int i = 0; - while (i < name.size() && - (absl::ascii_isalnum(name[i]) || name[i] == '_')) - ++i; - if (i > 0 && i == name.size()) { // safe field name - if (loc.empty()) { - loc = name; - } else { - absl::StrAppend(&loc, ".", name); - } - } else { - absl::StrAppend(&loc, "[\"", absl::CEscape(name), "\"]"); - } - } - - int array_index_now = now->array_index_; - if (ow_->IsRepeated(*(now->parent_field_)) && array_index_now > 0) { - absl::StrAppend(&loc, "[", array_index_now - 1, "]"); - } - } - - return loc; -} - -bool ProtoWriter::ProtoElement::IsOneofIndexTaken(int32_t index) { - return oneof_indices_[index]; -} - -void ProtoWriter::ProtoElement::TakeOneofIndex(int32_t index) { - oneof_indices_[index] = true; -} - -void ProtoWriter::InvalidName(absl::string_view unknown_name, - absl::string_view message) { - listener_->InvalidName(location(), unknown_name, message); -} - -void ProtoWriter::InvalidValue(absl::string_view type_name, - absl::string_view value) { - listener_->InvalidValue(location(), type_name, value); -} - -void ProtoWriter::MissingField(absl::string_view missing_name) { - listener_->MissingField(location(), missing_name); -} - -ProtoWriter* ProtoWriter::StartObject( - absl::string_view name) { - // Starting the root message. Create the root ProtoElement and return. - if (element_ == nullptr) { - if (!name.empty()) { - InvalidName(name, "Root element should not be named."); - } - element_.reset(new ProtoElement(typeinfo_, master_type_, this)); - return this; - } - - const google::protobuf::Field* field = BeginNamed(name, false); - - if (field == nullptr) return this; - - // Check to see if this field is a oneof and that no oneof in that group has - // already been set. - if (!ValidOneof(*field, name)) { - ++invalid_depth_; - return this; - } - - const google::protobuf::Type* type = LookupType(field); - if (type == nullptr) { - ++invalid_depth_; - InvalidName(name, absl::StrCat("Missing descriptor for field: ", - field->type_url())); - return this; - } - - return StartObjectField(*field, *type); -} - - -ProtoWriter* ProtoWriter::EndObject() { - if (invalid_depth_ > 0) { - --invalid_depth_; - return this; - } - - if (element_ != nullptr) { - element_.reset(element_->pop()); - } - - - // If ending the root element, - // then serialize the full message with calculated sizes. - if (element_ == nullptr) { - WriteRootMessage(); - } - return this; -} - -ProtoWriter* ProtoWriter::StartList( - absl::string_view name) { - - const google::protobuf::Field* field = BeginNamed(name, true); - - if (field == nullptr) return this; - - if (!ValidOneof(*field, name)) { - ++invalid_depth_; - return this; - } - - const google::protobuf::Type* type = LookupType(field); - if (type == nullptr) { - ++invalid_depth_; - InvalidName(name, absl::StrCat("Missing descriptor for field: ", - field->type_url())); - return this; - } - - return StartListField(*field, *type); -} - - -ProtoWriter* ProtoWriter::EndList() { - if (invalid_depth_ > 0) { - --invalid_depth_; - } else if (element_ != nullptr) { - element_.reset(element_->pop()); - } - return this; -} - -ProtoWriter* ProtoWriter::RenderDataPiece( - absl::string_view name, const DataPiece& data) { - absl::Status status; - if (invalid_depth_ > 0) return this; - - const google::protobuf::Field* field = Lookup(name); - - if (field == nullptr) return this; - - if (!ValidOneof(*field, name)) return this; - - const google::protobuf::Type* type = LookupType(field); - if (type == nullptr) { - InvalidName(name, absl::StrCat("Missing descriptor for field: ", - field->type_url())); - return this; - } - - return RenderPrimitiveField(*field, *type, data); -} - -bool ProtoWriter::ValidOneof(const google::protobuf::Field& field, - absl::string_view unnormalized_name) { - if (element_ == nullptr) return true; - - if (field.oneof_index() > 0) { - if (element_->IsOneofIndexTaken(field.oneof_index())) { - InvalidValue( - "oneof", - absl::StrCat( - "oneof field '", element_->type().oneofs(field.oneof_index() - 1), - "' is already set. Cannot set '", unnormalized_name, "'")); - return false; - } - element_->TakeOneofIndex(field.oneof_index()); - } - return true; -} - -bool ProtoWriter::IsRepeated(const google::protobuf::Field& field) { - return field.cardinality() == google::protobuf::Field::CARDINALITY_REPEATED; -} - -ProtoWriter* ProtoWriter::StartObjectField(const google::protobuf::Field& field, - const google::protobuf::Type& type) { - WriteTag(field); - element_.reset(new ProtoElement(element_.release(), &field, type, false)); - return this; -} - -ProtoWriter* ProtoWriter::StartListField(const google::protobuf::Field& field, - const google::protobuf::Type& type) { - element_.reset(new ProtoElement(element_.release(), &field, type, true)); - return this; -} - -absl::Status ProtoWriter::WriteEnum(int field_number, const DataPiece& data, - const google::protobuf::Enum* enum_type, - CodedOutputStream* stream, - bool use_lower_camel_for_enums, - bool case_insensitive_enum_parsing, - bool ignore_unknown_values) { - bool is_unknown_enum_value = false; - absl::StatusOr e = data.ToEnum( - enum_type, use_lower_camel_for_enums, case_insensitive_enum_parsing, - ignore_unknown_values, &is_unknown_enum_value); - if (e.ok() && !is_unknown_enum_value) { - WireFormatLite::WriteEnum(field_number, e.value(), stream); - } - return e.status(); -} - -ProtoWriter* ProtoWriter::RenderPrimitiveField( - const google::protobuf::Field& field, const google::protobuf::Type& type, - const DataPiece& data) { - absl::Status status; - - // Pushing a ProtoElement and then pop it off at the end for 2 purposes: - // error location reporting and required field accounting. - // - // For proto3, since there is no required field tracking, we only need to - // push ProtoElement for error cases. - if (!element_->proto3()) { - element_.reset(new ProtoElement(element_.release(), &field, type, false)); - } - - switch (field.kind()) { - case google::protobuf::Field::TYPE_INT32: { - status = WriteInt32(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field::TYPE_SFIXED32: { - status = WriteSFixed32(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field::TYPE_SINT32: { - status = WriteSInt32(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field::TYPE_FIXED32: { - status = WriteFixed32(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field::TYPE_UINT32: { - status = WriteUInt32(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field::TYPE_INT64: { - status = WriteInt64(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field::TYPE_SFIXED64: { - status = WriteSFixed64(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field::TYPE_SINT64: { - status = WriteSInt64(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field::TYPE_FIXED64: { - status = WriteFixed64(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field::TYPE_UINT64: { - status = WriteUInt64(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field::TYPE_DOUBLE: { - status = WriteDouble(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field::TYPE_FLOAT: { - status = WriteFloat(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field::TYPE_BOOL: { - status = WriteBool(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field::TYPE_BYTES: { - status = WriteBytes(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field::TYPE_STRING: { - status = WriteString(field.number(), data, stream_.get()); - break; - } - case google::protobuf::Field::TYPE_ENUM: { - status = WriteEnum( - field.number(), data, typeinfo_->GetEnumByTypeUrl(field.type_url()), - stream_.get(), use_lower_camel_for_enums_, - case_insensitive_enum_parsing_, ignore_unknown_enum_values_); - break; - } - default: // TYPE_GROUP, TYPE_MESSAGE, TYPE_UNKNOWN. - status = absl::InvalidArgumentError(data.ValueAsStringOrDefault("")); - } - - if (!status.ok()) { - // Push a ProtoElement for location reporting purposes. - if (element_->proto3()) { - element_.reset(new ProtoElement(element_.release(), &field, type, false)); - } - InvalidValue(field.type_url().empty() - ? google::protobuf::Field_Kind_Name(field.kind()) - : field.type_url(), - status.message()); - element_.reset(element()->pop()); - return this; - } - - if (!element_->proto3()) element_.reset(element()->pop()); - - return this; -} - -const google::protobuf::Field* ProtoWriter::BeginNamed(absl::string_view name, - bool is_list) { - if (invalid_depth_ > 0) { - ++invalid_depth_; - return nullptr; - } - const google::protobuf::Field* field = Lookup(name); - if (field == nullptr) { - ++invalid_depth_; - // InvalidName() already called in Lookup(). - return nullptr; - } - if (is_list && !IsRepeated(*field)) { - ++invalid_depth_; - InvalidName(name, "Proto field is not repeating, cannot start list."); - return nullptr; - } - return field; -} - -const google::protobuf::Field* ProtoWriter::Lookup( - absl::string_view unnormalized_name) { - ProtoElement* e = element(); - if (e == nullptr) { - InvalidName(unnormalized_name, "Root element must be a message."); - return nullptr; - } - if (unnormalized_name.empty()) { - // Objects in repeated field inherit the same field descriptor. - if (e->parent_field() == nullptr) { - InvalidName(unnormalized_name, "Proto fields must have a name."); - } else if (!IsRepeated(*e->parent_field())) { - InvalidName(unnormalized_name, "Proto fields must have a name."); - return nullptr; - } - return e->parent_field(); - } - const google::protobuf::Field* field = - typeinfo_->FindField(&e->type(), unnormalized_name); - if (field == nullptr && !ignore_unknown_fields_) { - InvalidName(unnormalized_name, "Cannot find field."); - } - return field; -} - -const google::protobuf::Type* ProtoWriter::LookupType( - const google::protobuf::Field* field) { - return ((field->kind() == google::protobuf::Field::TYPE_MESSAGE || - field->kind() == google::protobuf::Field::TYPE_GROUP) - ? typeinfo_->GetTypeByTypeUrl(field->type_url()) - : &element_->type()); -} - -void ProtoWriter::WriteRootMessage() { - GOOGLE_DCHECK(!done_); - int curr_pos = 0; - // Calls the destructor of CodedOutputStream to remove any uninitialized - // memory from the Cord before we read it. - stream_.reset(nullptr); - const void* data; - int length; - io::ArrayInputStream input_stream(buffer_.data(), buffer_.size()); - while (input_stream.Next(&data, &length)) { - if (length == 0) continue; - int num_bytes = length; - // Write up to where we need to insert the size field. - // The number of bytes we may write is the smaller of: - // - the current fragment size - // - the distance to the next position where a size field needs to be - // inserted. - if (!size_insert_.empty() && - size_insert_.front().pos - curr_pos < num_bytes) { - num_bytes = size_insert_.front().pos - curr_pos; - } - output_->Append(static_cast(data), num_bytes); - if (num_bytes < length) { - input_stream.BackUp(length - num_bytes); - } - curr_pos += num_bytes; - // Insert the size field. - // size_insert_.front(): the next pair to be written. - // size_insert_.front().pos: position of the size field. - // size_insert_.front().size: the size (integer) to be inserted. - if (!size_insert_.empty() && curr_pos == size_insert_.front().pos) { - // Varint32 occupies at most 10 bytes. - uint8_t insert_buffer[10]; - uint8_t* insert_buffer_pos = CodedOutputStream::WriteVarint32ToArray( - size_insert_.front().size, insert_buffer); - output_->Append(reinterpret_cast(insert_buffer), - insert_buffer_pos - insert_buffer); - size_insert_.pop_front(); - } - } - output_->Flush(); - stream_.reset(new CodedOutputStream(&adapter_)); - done_ = true; -} - -void ProtoWriter::WriteTag(const google::protobuf::Field& field) { - WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType( - static_cast(field.kind())); - stream_->WriteTag(WireFormatLite::MakeTag(field.number(), wire_type)); -} - - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/util/internal/proto_writer.h b/src/google/protobuf/util/internal/proto_writer.h deleted file mode 100644 index 81c8b25120..0000000000 --- a/src/google/protobuf/util/internal/proto_writer.h +++ /dev/null @@ -1,391 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTO_WRITER_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTO_WRITER_H__ - -#include -#include -#include -#include -#include - -#include "google/protobuf/type.pb.h" -#include "google/protobuf/io/coded_stream.h" -#include "google/protobuf/io/zero_copy_stream_impl.h" -#include "google/protobuf/descriptor.h" -#include "absl/status/status.h" -#include "google/protobuf/stubs/bytestream.h" -#include "google/protobuf/port.h" -#include "google/protobuf/util/internal/datapiece.h" -#include "google/protobuf/util/internal/error_listener.h" -#include "google/protobuf/util/internal/structured_objectwriter.h" -#include "google/protobuf/util/internal/type_info.h" -#include "google/protobuf/util/type_resolver.h" - - -// Must be included last. -#include "google/protobuf/port_def.inc" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - - -class ObjectLocationTracker; - -// An ObjectWriter that can write protobuf bytes directly from writer events. -// This class does not support special types like Struct or Map. However, since -// this class supports raw protobuf, it can be used to provide support for -// special types by inheriting from it or by wrapping it. -// -// It also supports streaming. -class PROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { - public: -// Constructor. Does not take ownership of any parameter passed in. - ProtoWriter(TypeResolver* type_resolver, const google::protobuf::Type& type, - strings::ByteSink* output, ErrorListener* listener); - ProtoWriter() = delete; - ProtoWriter(const ProtoWriter&) = delete; - ProtoWriter& operator=(const ProtoWriter&) = delete; - ~ProtoWriter() override; - - // ObjectWriter methods. - ProtoWriter* StartObject(absl::string_view name) override; - ProtoWriter* EndObject() override; - ProtoWriter* StartList(absl::string_view name) override; - ProtoWriter* EndList() override; - ProtoWriter* RenderBool(absl::string_view name, bool value) override { - return RenderDataPiece(name, DataPiece(value)); - } - ProtoWriter* RenderInt32(absl::string_view name, int32_t value) override { - return RenderDataPiece(name, DataPiece(value)); - } - ProtoWriter* RenderUint32(absl::string_view name, uint32_t value) override { - return RenderDataPiece(name, DataPiece(value)); - } - ProtoWriter* RenderInt64(absl::string_view name, int64_t value) override { - return RenderDataPiece(name, DataPiece(value)); - } - ProtoWriter* RenderUint64(absl::string_view name, uint64_t value) override { - return RenderDataPiece(name, DataPiece(value)); - } - ProtoWriter* RenderDouble(absl::string_view name, double value) override { - return RenderDataPiece(name, DataPiece(value)); - } - ProtoWriter* RenderFloat(absl::string_view name, float value) override { - return RenderDataPiece(name, DataPiece(value)); - } - ProtoWriter* RenderString(absl::string_view name, - absl::string_view value) override { - return RenderDataPiece(name, - DataPiece(value, use_strict_base64_decoding())); - } - - ProtoWriter* RenderBytes(absl::string_view name, - absl::string_view value) override { - return RenderDataPiece( - name, DataPiece(value, false, use_strict_base64_decoding())); - } - - ProtoWriter* RenderNull(absl::string_view name) override { - return RenderDataPiece(name, DataPiece::NullData()); - } - - - // Renders a DataPiece 'value' into a field whose wire type is determined - // from the given field 'name'. - virtual ProtoWriter* RenderDataPiece(absl::string_view name, - const DataPiece& data); - - - // Returns the location tracker to use for tracking locations for errors. - const LocationTrackerInterface& location() { - return element_ != nullptr ? *element_ : *tracker_; - } - - // When true, we finished writing to output a complete message. - bool done() override { return done_; } - - // Returns the proto stream object. - io::CodedOutputStream* stream() { return stream_.get(); } - - // Getters and mutators of invalid_depth_. - void IncrementInvalidDepth() { ++invalid_depth_; } - void DecrementInvalidDepth() { --invalid_depth_; } - int invalid_depth() { return invalid_depth_; } - - ErrorListener* listener() { return listener_; } - - const TypeInfo* typeinfo() { return typeinfo_; } - - void set_ignore_unknown_fields(bool ignore_unknown_fields) { - ignore_unknown_fields_ = ignore_unknown_fields; - } - - bool ignore_unknown_fields() { return ignore_unknown_fields_; } - - void set_ignore_unknown_enum_values(bool ignore_unknown_enum_values) { - ignore_unknown_enum_values_ = ignore_unknown_enum_values; - } - - void set_use_lower_camel_for_enums(bool use_lower_camel_for_enums) { - use_lower_camel_for_enums_ = use_lower_camel_for_enums; - } - - void set_case_insensitive_enum_parsing(bool case_insensitive_enum_parsing) { - case_insensitive_enum_parsing_ = case_insensitive_enum_parsing; - } - - void set_use_json_name_in_missing_fields( - bool use_json_name_in_missing_fields) { - use_json_name_in_missing_fields_ = use_json_name_in_missing_fields; - } - - protected: - class PROTOBUF_EXPORT ProtoElement : public BaseElement, - public LocationTrackerInterface { - public: - // Constructor for the root element. No parent nor field. - ProtoElement(const TypeInfo* typeinfo, const google::protobuf::Type& type, - ProtoWriter* enclosing); - - // Constructor for a field of an element. - ProtoElement(ProtoElement* parent, const google::protobuf::Field* field, - const google::protobuf::Type& type, bool is_list); - ProtoElement() = delete; - ProtoElement(const ProtoElement&) = delete; - ProtoElement& operator=(const ProtoElement&) = delete; - - ~ProtoElement() override {} - - // Called just before the destructor for clean up: - // - reports any missing required fields - // - computes the space needed by the size field, and augment the - // length of all parent messages by this additional space. - // - releases and returns the parent pointer. - ProtoElement* pop(); - - // Accessors - // parent_field() may be nullptr if we are at root. - const google::protobuf::Field* parent_field() const { - return parent_field_; - } - const google::protobuf::Type& type() const { return type_; } - - // Registers field for accounting required fields. - void RegisterField(const google::protobuf::Field* field); - - // To report location on error messages. - std::string ToString() const override; - - ProtoElement* parent() const override { - return static_cast(BaseElement::parent()); - } - - // Returns true if the index is already taken by a preceding oneof input. - bool IsOneofIndexTaken(int32_t index); - - // Marks the oneof 'index' as taken. Future inputs to this oneof will - // generate an error. - void TakeOneofIndex(int32_t index); - - bool proto3() { return proto3_; } - - private: - // Used for access to variables of the enclosing instance of - // ProtoWriter. - ProtoWriter* ow_; - - // Describes the element as a field in the parent message. - // parent_field_ is nullptr if and only if this element is the root element. - const google::protobuf::Field* parent_field_; - - // TypeInfo to lookup types. - const TypeInfo* typeinfo_; - - // Whether the type_ is proto3 or not. - bool proto3_; - - // Additional variables if this element is a message: - // (Root element is always a message). - // type_ : the type of this element. - // required_fields_ : set of required fields. - // size_index_ : index into ProtoWriter::size_insert_ - // for later insertion of serialized message length. - const google::protobuf::Type& type_; - std::unordered_set required_fields_; - const int size_index_; - - // Tracks position in repeated fields, needed for LocationTrackerInterface. - int array_index_; - - // Set of oneof indices already seen for the type_. Used to validate - // incoming messages so no more than one oneof is set. - std::vector oneof_indices_; - }; - - // Container for inserting 'size' information at the 'pos' position. - struct SizeInfo { - const int pos; - int size; - }; - - ProtoWriter(const TypeInfo* typeinfo, const google::protobuf::Type& type, - strings::ByteSink* output, ErrorListener* listener); - - ProtoElement* element() override { return element_.get(); } - - // Helper methods for calling ErrorListener. See error_listener.h. - void InvalidName(absl::string_view unknown_name, absl::string_view message); - void InvalidValue(absl::string_view type_name, absl::string_view value); - void MissingField(absl::string_view missing_name); - - // Common code for BeginObject() and BeginList() that does invalid_depth_ - // bookkeeping associated with name lookup. - const google::protobuf::Field* BeginNamed(absl::string_view name, - bool is_list); - - // Lookup the field in the current element. Looks in the base descriptor - // and in any extension. This will report an error if the field cannot be - // found when ignore_unknown_names_ is false or if multiple matching - // extensions are found. - const google::protobuf::Field* Lookup(absl::string_view name); - - // Lookup the field type in the type descriptor. Returns nullptr if the type - // is not known. - const google::protobuf::Type* LookupType( - const google::protobuf::Field* field); - - // Write serialized output to the final output ByteSink, inserting all - // the size information for nested messages that are missing from the - // intermediate Cord buffer. - void WriteRootMessage(); - - // Helper method to write proto tags based on the given field. - void WriteTag(const google::protobuf::Field& field); - - - // Returns true if the field for type_ can be set as a oneof. If field is not - // a oneof type, this function does nothing and returns true. - // If another field for this oneof is already set, this function returns - // false. It also calls the appropriate error callback. - // unnormalized_name is used for error string. - bool ValidOneof(const google::protobuf::Field& field, - absl::string_view unnormalized_name); - - // Returns true if the field is repeated. - bool IsRepeated(const google::protobuf::Field& field); - - // Starts an object given the field and the enclosing type. - ProtoWriter* StartObjectField(const google::protobuf::Field& field, - const google::protobuf::Type& type); - - // Starts a list given the field and the enclosing type. - ProtoWriter* StartListField(const google::protobuf::Field& field, - const google::protobuf::Type& type); - - // Renders a primitive field given the field and the enclosing type. - ProtoWriter* RenderPrimitiveField(const google::protobuf::Field& field, - const google::protobuf::Type& type, - const DataPiece& data); - - private: - // Writes an ENUM field, including tag, to the stream. - static absl::Status WriteEnum(int field_number, const DataPiece& data, - const google::protobuf::Enum* enum_type, - io::CodedOutputStream* stream, - bool use_lower_camel_for_enums, - bool case_insensitive_enum_parsing, - bool ignore_unknown_values); - - // Variables for describing the structure of the input tree: - // master_type_: descriptor for the whole protobuf message. - // typeinfo_ : the TypeInfo object to lookup types. - const google::protobuf::Type& master_type_; - const TypeInfo* typeinfo_; - // Whether we own the typeinfo_ object. - bool own_typeinfo_; - - // Indicates whether we finished writing root message completely. - bool done_; - - // If true, don't report unknown field names to the listener. - bool ignore_unknown_fields_; - - // If true, don't report unknown enum values to the listener. - bool ignore_unknown_enum_values_; - - // If true, check if enum name in camel case or without underscore matches the - // field name. - bool use_lower_camel_for_enums_; - - // If true, check if enum name in UPPER_CASE matches the field name. - bool case_insensitive_enum_parsing_; - - // If true, use the json name in missing fields errors. - bool use_json_name_in_missing_fields_; - - // Variable for internal state processing: - // element_ : the current element. - // size_insert_: sizes of nested messages. - // pos - position to insert the size field. - // size - size value to be inserted. - std::unique_ptr element_; - std::deque size_insert_; - - // Variables for output generation: - // output_ : pointer to an external ByteSink for final user-visible output. - // buffer_ : buffer holding partial message before being ready for output_. - // adapter_ : internal adapter between CodedOutputStream and buffer_. - // stream_ : wrapper for writing tags and other encodings in wire format. - strings::ByteSink* output_; - std::string buffer_; - io::StringOutputStream adapter_; - std::unique_ptr stream_; - - // Variables for error tracking and reporting: - // listener_ : a place to report any errors found. - // invalid_depth_: number of enclosing invalid nested messages. - // tracker_ : the root location tracker interface. - ErrorListener* listener_; - int invalid_depth_; - std::unique_ptr tracker_; -}; - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google - -#include "google/protobuf/port_undef.inc" - -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTO_WRITER_H__ diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc deleted file mode 100644 index 367205fe4c..0000000000 --- a/src/google/protobuf/util/internal/protostream_objectsource.cc +++ /dev/null @@ -1,1124 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google/protobuf/util/internal/protostream_objectsource.h" - -#include -#include -#include - -#include "google/protobuf/stubs/logging.h" -#include "google/protobuf/stubs/common.h" -#include "google/protobuf/io/coded_stream.h" -#include "google/protobuf/io/zero_copy_stream_impl.h" -#include "google/protobuf/descriptor.h" -#include "google/protobuf/unknown_field_set.h" -#include "google/protobuf/wire_format.h" -#include "google/protobuf/wire_format_lite.h" -#include "google/protobuf/stubs/strutil.h" -#include "absl/base/call_once.h" -#include "absl/base/casts.h" -#include "absl/status/status.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/str_format.h" -#include "absl/strings/string_view.h" -#include "absl/time/time.h" -#include "google/protobuf/util/internal/constants.h" -#include "google/protobuf/util/internal/field_mask_utility.h" -#include "google/protobuf/util/internal/utility.h" -#include "google/protobuf/stubs/status_macros.h" - - -// Must be included last. -#include "google/protobuf/port_def.inc" - - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -using ::PROTOBUF_NAMESPACE_ID::internal::WireFormat; -using ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite; - -namespace { - -static int kDefaultMaxRecursionDepth = 64; - -// Finds a field with the given number. nullptr if none found. -const google::protobuf::Field* FindFieldByNumber( - const google::protobuf::Type& type, int number); - -// Returns true if the field is packable. -bool IsPackable(const google::protobuf::Field& field); - -// Finds an enum value with the given number. nullptr if none found. -const google::protobuf::EnumValue* FindEnumValueByNumber( - const google::protobuf::Enum& tech_enum, int number); - -// Utility function to format nanos. -std::string FormatNanos(uint32_t nanos, bool with_trailing_zeros); - -absl::StatusOr MapKeyDefaultValueAsString( - const google::protobuf::Field& field) { - switch (field.kind()) { - case google::protobuf::Field::TYPE_BOOL: - return std::string("false"); - case google::protobuf::Field::TYPE_INT32: - case google::protobuf::Field::TYPE_INT64: - case google::protobuf::Field::TYPE_UINT32: - case google::protobuf::Field::TYPE_UINT64: - case google::protobuf::Field::TYPE_SINT32: - case google::protobuf::Field::TYPE_SINT64: - case google::protobuf::Field::TYPE_SFIXED32: - case google::protobuf::Field::TYPE_SFIXED64: - case google::protobuf::Field::TYPE_FIXED32: - case google::protobuf::Field::TYPE_FIXED64: - return std::string("0"); - case google::protobuf::Field::TYPE_STRING: - return std::string(); - default: - return absl::InternalError("Invalid map key type."); - } -} -} // namespace - - -ProtoStreamObjectSource::ProtoStreamObjectSource( - io::CodedInputStream* stream, TypeResolver* type_resolver, - const google::protobuf::Type& type, const RenderOptions& render_options) - : stream_(stream), - typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), - own_typeinfo_(true), - type_(type), - render_options_(render_options), - recursion_depth_(0), - max_recursion_depth_(kDefaultMaxRecursionDepth) { - GOOGLE_LOG_IF(DFATAL, stream == nullptr) << "Input stream is nullptr."; -} - -ProtoStreamObjectSource::ProtoStreamObjectSource( - io::CodedInputStream* stream, const TypeInfo* typeinfo, - const google::protobuf::Type& type, const RenderOptions& render_options) - : stream_(stream), - typeinfo_(typeinfo), - own_typeinfo_(false), - type_(type), - render_options_(render_options), - recursion_depth_(0), - max_recursion_depth_(kDefaultMaxRecursionDepth) { - GOOGLE_LOG_IF(DFATAL, stream == nullptr) << "Input stream is nullptr."; -} - -ProtoStreamObjectSource::~ProtoStreamObjectSource() { - if (own_typeinfo_) { - delete typeinfo_; - } -} - -absl::Status ProtoStreamObjectSource::NamedWriteTo(absl::string_view name, - ObjectWriter* ow) const { - return WriteMessage(type_, name, 0, true, ow); -} - -const google::protobuf::Field* ProtoStreamObjectSource::FindAndVerifyField( - const google::protobuf::Type& type, uint32_t tag) const { - // Lookup the new field in the type by tag number. - const google::protobuf::Field* field = FindFieldByNumber(type, tag >> 3); - // Verify if the field corresponds to the wire type in tag. - // If there is any discrepancy, mark the field as not found. - if (field != nullptr) { - WireFormatLite::WireType expected_type = - WireFormatLite::WireTypeForFieldType( - static_cast(field->kind())); - WireFormatLite::WireType actual_type = WireFormatLite::GetTagWireType(tag); - if (actual_type != expected_type && - (!IsPackable(*field) || - actual_type != WireFormatLite::WIRETYPE_LENGTH_DELIMITED)) { - field = nullptr; - } - } - return field; -} - -absl::Status ProtoStreamObjectSource::WriteMessage( - const google::protobuf::Type& type, absl::string_view name, - const uint32_t end_tag, bool include_start_and_end, - ObjectWriter* ow) const { - - const TypeRenderer* type_renderer = FindTypeRenderer(type.name()); - if (type_renderer != nullptr) { - return (*type_renderer)(this, type, name, ow); - } - - const google::protobuf::Field* field = nullptr; - std::string field_name; - // last_tag set to dummy value that is different from tag. - uint32_t tag = stream_->ReadTag(), last_tag = tag + 1; - UnknownFieldSet unknown_fields; - - - if (include_start_and_end) { - ow->StartObject(name); - } - while (tag != end_tag && tag != 0) { - if (tag != last_tag) { // Update field only if tag is changed. - last_tag = tag; - field = FindAndVerifyField(type, tag); - if (field != nullptr) { - if (render_options_.preserve_proto_field_names) { - field_name = field->name(); - } else { - field_name = field->json_name(); - } - } - } - if (field == nullptr) { - // If we didn't find a field, skip this unknown tag. - // TODO(wpoon): Check return boolean value. - WireFormat::SkipField( - stream_, tag, - nullptr); - tag = stream_->ReadTag(); - continue; - } - - if (field->cardinality() == google::protobuf::Field::CARDINALITY_REPEATED) { - if (IsMap(*field)) { - ow->StartObject(field_name); - ASSIGN_OR_RETURN(tag, RenderMap(field, field_name, tag, ow)); - ow->EndObject(); - } else { - ASSIGN_OR_RETURN(tag, RenderList(field, field_name, tag, ow)); - } - } else { - // Render the field. - RETURN_IF_ERROR(RenderField(field, field_name, ow)); - tag = stream_->ReadTag(); - } - } - - - if (include_start_and_end) { - ow->EndObject(); - } - return absl::Status(); -} - -absl::StatusOr ProtoStreamObjectSource::RenderList( - const google::protobuf::Field* field, absl::string_view name, - uint32_t list_tag, ObjectWriter* ow) const { - uint32_t tag_to_return = 0; - ow->StartList(name); - if (IsPackable(*field) && - list_tag == - WireFormatLite::MakeTag(field->number(), - WireFormatLite::WIRETYPE_LENGTH_DELIMITED)) { - RETURN_IF_ERROR(RenderPacked(field, ow)); - // Since packed fields have a single tag, read another tag from stream to - // return. - tag_to_return = stream_->ReadTag(); - } else { - do { - RETURN_IF_ERROR(RenderField(field, "", ow)); - } while ((tag_to_return = stream_->ReadTag()) == list_tag); - } - ow->EndList(); - return tag_to_return; -} - -absl::StatusOr ProtoStreamObjectSource::RenderMap( - const google::protobuf::Field* field, absl::string_view /* name */, - uint32_t list_tag, ObjectWriter* ow) const { - const google::protobuf::Type* field_type = - typeinfo_->GetTypeByTypeUrl(field->type_url()); - uint32_t tag_to_return = 0; - do { - // Render map entry message type. - uint32_t buffer32; - stream_->ReadVarint32(&buffer32); // message length - int old_limit = stream_->PushLimit(buffer32); - std::string map_key; - for (uint32_t tag = stream_->ReadTag(); tag != 0; - tag = stream_->ReadTag()) { - const google::protobuf::Field* map_entry_field = - FindAndVerifyField(*field_type, tag); - if (map_entry_field == nullptr) { - WireFormat::SkipField(stream_, tag, nullptr); - continue; - } - // Map field numbers are key = 1 and value = 2 - if (map_entry_field->number() == 1) { - map_key = ReadFieldValueAsString(*map_entry_field); - } else if (map_entry_field->number() == 2) { - if (map_key.empty()) { - // An absent map key is treated as the default. - const google::protobuf::Field* key_field = - FindFieldByNumber(*field_type, 1); - if (key_field == nullptr) { - // The Type info for this map entry is incorrect. It should always - // have a field named "key" and with field number 1. - return absl::InternalError("Invalid map entry."); - } - ASSIGN_OR_RETURN(map_key, MapKeyDefaultValueAsString(*key_field)); - } - RETURN_IF_ERROR(RenderField(map_entry_field, map_key, ow)); - } else { - // The Type info for this map entry is incorrect. It should contain - // exactly two fields with field number 1 and 2. - return absl::InternalError("Invalid map entry."); - } - } - stream_->PopLimit(old_limit); - } while ((tag_to_return = stream_->ReadTag()) == list_tag); - return tag_to_return; -} - -absl::Status ProtoStreamObjectSource::RenderPacked( - const google::protobuf::Field* field, ObjectWriter* ow) const { - uint32_t length; - stream_->ReadVarint32(&length); - int old_limit = stream_->PushLimit(length); - while (stream_->BytesUntilLimit() > 0) { - RETURN_IF_ERROR(RenderField(field, absl::string_view(), ow)); - } - stream_->PopLimit(old_limit); - return absl::Status(); -} - -absl::Status ProtoStreamObjectSource::RenderTimestamp( - const ProtoStreamObjectSource* os, const google::protobuf::Type& type, - absl::string_view field_name, ObjectWriter* ow) { - std::pair p = os->ReadSecondsAndNanos(type); - int64_t seconds = p.first; - int32_t nanos = p.second; - if (seconds > kTimestampMaxSeconds || seconds < kTimestampMinSeconds) { - return absl::InternalError(absl::StrCat( - "Timestamp seconds exceeds limit for field: ", field_name)); - } - - if (nanos < 0 || nanos >= kNanosPerSecond) { - return absl::InternalError( - absl::StrCat("Timestamp nanos exceeds limit for field: ", field_name)); - } - - absl::Time tm = absl::FromUnixSeconds(seconds); - std::string formatted_seconds = - absl::FormatTime(kRfc3339TimeFormat, tm, absl::UTCTimeZone()); - std::string formatted_time = absl::StrFormat( - "%s%sZ", formatted_seconds.c_str(), - FormatNanos( - nanos, - false - ) - .c_str()); - ow->RenderString(field_name, formatted_time); - return absl::Status(); -} - -absl::Status ProtoStreamObjectSource::RenderDuration( - const ProtoStreamObjectSource* os, const google::protobuf::Type& type, - absl::string_view field_name, ObjectWriter* ow) { - std::pair p = os->ReadSecondsAndNanos(type); - int64_t seconds = p.first; - int32_t nanos = p.second; - if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds) { - return absl::InternalError( - absl::StrCat("Duration seconds exceeds limit for field: ", field_name)); - } - - if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) { - return absl::InternalError( - absl::StrCat("Duration nanos exceeds limit for field: ", field_name)); - } - - std::string sign = ""; - if (seconds < 0) { - if (nanos > 0) { - return absl::InternalError( - absl::StrCat("Duration nanos is non-negative, but seconds is " - "negative for field: ", - field_name)); - } - sign = "-"; - seconds = -seconds; - nanos = -nanos; - } else if (seconds == 0 && nanos < 0) { - sign = "-"; - nanos = -nanos; - } - std::string formatted_duration = absl::StrFormat( - "%s%lld%ss", sign.c_str(), static_cast(seconds), // NOLINT - FormatNanos( - nanos, - false - ) - .c_str()); - ow->RenderString(field_name, formatted_duration); - return absl::Status(); -} - -absl::Status ProtoStreamObjectSource::RenderDouble( - const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/, - absl::string_view field_name, ObjectWriter* ow) { - uint32_t tag = os->stream_->ReadTag(); - uint64_t buffer64 = 0; // default value of Double wrapper value - if (tag != 0) { - os->stream_->ReadLittleEndian64(&buffer64); - os->stream_->ReadTag(); - } - ow->RenderDouble(field_name, absl::bit_cast(buffer64)); - return absl::Status(); -} - -absl::Status ProtoStreamObjectSource::RenderFloat( - const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/, - absl::string_view field_name, ObjectWriter* ow) { - uint32_t tag = os->stream_->ReadTag(); - uint32_t buffer32 = 0; // default value of Float wrapper value - if (tag != 0) { - os->stream_->ReadLittleEndian32(&buffer32); - os->stream_->ReadTag(); - } - ow->RenderFloat(field_name, absl::bit_cast(buffer32)); - return absl::Status(); -} - -absl::Status ProtoStreamObjectSource::RenderInt64( - const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/, - absl::string_view field_name, ObjectWriter* ow) { - uint32_t tag = os->stream_->ReadTag(); - uint64_t buffer64 = 0; // default value of Int64 wrapper value - if (tag != 0) { - os->stream_->ReadVarint64(&buffer64); - os->stream_->ReadTag(); - } - ow->RenderInt64(field_name, absl::bit_cast(buffer64)); - return absl::Status(); -} - -absl::Status ProtoStreamObjectSource::RenderUInt64( - const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/, - absl::string_view field_name, ObjectWriter* ow) { - uint32_t tag = os->stream_->ReadTag(); - uint64_t buffer64 = 0; // default value of UInt64 wrapper value - if (tag != 0) { - os->stream_->ReadVarint64(&buffer64); - os->stream_->ReadTag(); - } - ow->RenderUint64(field_name, absl::bit_cast(buffer64)); - return absl::Status(); -} - -absl::Status ProtoStreamObjectSource::RenderInt32( - const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/, - absl::string_view field_name, ObjectWriter* ow) { - uint32_t tag = os->stream_->ReadTag(); - uint32_t buffer32 = 0; // default value of Int32 wrapper value - if (tag != 0) { - os->stream_->ReadVarint32(&buffer32); - os->stream_->ReadTag(); - } - ow->RenderInt32(field_name, absl::bit_cast(buffer32)); - return absl::Status(); -} - -absl::Status ProtoStreamObjectSource::RenderUInt32( - const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/, - absl::string_view field_name, ObjectWriter* ow) { - uint32_t tag = os->stream_->ReadTag(); - uint32_t buffer32 = 0; // default value of UInt32 wrapper value - if (tag != 0) { - os->stream_->ReadVarint32(&buffer32); - os->stream_->ReadTag(); - } - ow->RenderUint32(field_name, absl::bit_cast(buffer32)); - return absl::Status(); -} - -absl::Status ProtoStreamObjectSource::RenderBool( - const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/, - absl::string_view field_name, ObjectWriter* ow) { - uint32_t tag = os->stream_->ReadTag(); - uint64_t buffer64 = 0; // results in 'false' value as default, which is the - // default value of Bool wrapper - if (tag != 0) { - os->stream_->ReadVarint64(&buffer64); - os->stream_->ReadTag(); - } - ow->RenderBool(field_name, buffer64 != 0); - return absl::Status(); -} - -absl::Status ProtoStreamObjectSource::RenderString( - const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/, - absl::string_view field_name, ObjectWriter* ow) { - uint32_t tag = os->stream_->ReadTag(); - uint32_t buffer32; - std::string str; // default value of empty for String wrapper - if (tag != 0) { - os->stream_->ReadVarint32(&buffer32); // string size. - os->stream_->ReadString(&str, buffer32); - os->stream_->ReadTag(); - } - ow->RenderString(field_name, str); - return absl::Status(); -} - -absl::Status ProtoStreamObjectSource::RenderBytes( - const ProtoStreamObjectSource* os, const google::protobuf::Type& /*type*/, - absl::string_view field_name, ObjectWriter* ow) { - uint32_t tag = os->stream_->ReadTag(); - uint32_t buffer32; - std::string str; - if (tag != 0) { - os->stream_->ReadVarint32(&buffer32); - os->stream_->ReadString(&str, buffer32); - os->stream_->ReadTag(); - } - ow->RenderBytes(field_name, str); - return absl::Status(); -} - -absl::Status ProtoStreamObjectSource::RenderStruct( - const ProtoStreamObjectSource* os, const google::protobuf::Type& type, - absl::string_view field_name, ObjectWriter* ow) { - const google::protobuf::Field* field = nullptr; - uint32_t tag = os->stream_->ReadTag(); - ow->StartObject(field_name); - while (tag != 0) { - field = os->FindAndVerifyField(type, tag); - if (field == nullptr) { - WireFormat::SkipField(os->stream_, tag, nullptr); - tag = os->stream_->ReadTag(); - continue; - } - // google.protobuf.Struct has only one field that is a map. Hence we use - // RenderMap to render that field. - if (os->IsMap(*field)) { - ASSIGN_OR_RETURN(tag, os->RenderMap(field, field_name, tag, ow)); - } - } - ow->EndObject(); - return absl::Status(); -} - -absl::Status ProtoStreamObjectSource::RenderStructValue( - const ProtoStreamObjectSource* os, const google::protobuf::Type& type, - absl::string_view field_name, ObjectWriter* ow) { - const google::protobuf::Field* field = nullptr; - for (uint32_t tag = os->stream_->ReadTag(); tag != 0; - tag = os->stream_->ReadTag()) { - field = os->FindAndVerifyField(type, tag); - if (field == nullptr) { - WireFormat::SkipField(os->stream_, tag, nullptr); - continue; - } - RETURN_IF_ERROR(os->RenderField(field, field_name, ow)); - } - return absl::Status(); -} - -// TODO(skarvaje): Avoid code duplication of for loops and SkipField logic. -absl::Status ProtoStreamObjectSource::RenderStructListValue( - const ProtoStreamObjectSource* os, const google::protobuf::Type& type, - absl::string_view field_name, ObjectWriter* ow) { - uint32_t tag = os->stream_->ReadTag(); - - // Render empty list when we find empty ListValue message. - if (tag == 0) { - ow->StartList(field_name); - ow->EndList(); - return absl::Status(); - } - - while (tag != 0) { - const google::protobuf::Field* field = os->FindAndVerifyField(type, tag); - if (field == nullptr) { - WireFormat::SkipField(os->stream_, tag, nullptr); - tag = os->stream_->ReadTag(); - continue; - } - ASSIGN_OR_RETURN(tag, os->RenderList(field, field_name, tag, ow)); - } - return absl::Status(); -} - -absl::Status ProtoStreamObjectSource::RenderAny( - const ProtoStreamObjectSource* os, const google::protobuf::Type& type, - absl::string_view field_name, ObjectWriter* ow) { - // An Any is of the form { string type_url = 1; bytes value = 2; } - uint32_t tag; - std::string type_url; - std::string value; - - // First read out the type_url and value from the proto stream - for (tag = os->stream_->ReadTag(); tag != 0; tag = os->stream_->ReadTag()) { - const google::protobuf::Field* field = os->FindAndVerifyField(type, tag); - if (field == nullptr) { - WireFormat::SkipField(os->stream_, tag, nullptr); - continue; - } - // 'type_url' has field number of 1 and 'value' has field number 2 - // //google/protobuf/any.proto - if (field->number() == 1) { - // read type_url - uint32_t type_url_size; - os->stream_->ReadVarint32(&type_url_size); - os->stream_->ReadString(&type_url, type_url_size); - } else if (field->number() == 2) { - // read value - uint32_t value_size; - os->stream_->ReadVarint32(&value_size); - os->stream_->ReadString(&value, value_size); - } - } - - // If there is no value, we don't lookup the type, we just output it (if - // present). If both type and value are empty we output an empty object. - if (value.empty()) { - ow->StartObject(field_name); - if (!type_url.empty()) { - ow->RenderString("@type", type_url); - } - ow->EndObject(); - return absl::Status(); - } - - // If there is a value but no type, we cannot render it, so report an error. - if (type_url.empty()) { - // TODO(sven): Add an external message once those are ready. - return absl::InternalError("Invalid Any, the type_url is missing."); - } - - absl::StatusOr resolved_type = - os->typeinfo_->ResolveTypeUrl(type_url); - - if (!resolved_type.ok()) { - // Convert into an internal error, since this means the backend gave us - // an invalid response (missing or invalid type information). - return absl::InternalError(resolved_type.status().message()); - } - // nested_type cannot be null at this time. - const google::protobuf::Type* nested_type = resolved_type.value(); - - io::ArrayInputStream zero_copy_stream(value.data(), value.size()); - io::CodedInputStream in_stream(&zero_copy_stream); - // We know the type so we can render it. Recursively parse the nested stream - // using a nested ProtoStreamObjectSource using our nested type information. - ProtoStreamObjectSource nested_os(&in_stream, os->typeinfo_, *nested_type, - os->render_options_); - - // We manually call start and end object here so we can inject the @type. - ow->StartObject(field_name); - ow->RenderString("@type", type_url); - absl::Status result = - nested_os.WriteMessage(nested_os.type_, "value", 0, false, ow); - ow->EndObject(); - return result; -} - -absl::Status ProtoStreamObjectSource::RenderFieldMask( - const ProtoStreamObjectSource* os, const google::protobuf::Type& type, - absl::string_view field_name, ObjectWriter* ow) { - std::string combined; - uint32_t buffer32; - uint32_t paths_field_tag = 0; - for (uint32_t tag = os->stream_->ReadTag(); tag != 0; - tag = os->stream_->ReadTag()) { - if (paths_field_tag == 0) { - const google::protobuf::Field* field = os->FindAndVerifyField(type, tag); - if (field != nullptr && field->number() == 1 && - field->name() == "paths") { - paths_field_tag = tag; - } - } - if (paths_field_tag != tag) { - return absl::InternalError("Invalid FieldMask, unexpected field."); - } - std::string str; - os->stream_->ReadVarint32(&buffer32); // string size. - os->stream_->ReadString(&str, buffer32); - if (!combined.empty()) { - combined.append(","); - } - combined.append(ConvertFieldMaskPath(str, &ToCamelCase)); - } - ow->RenderString(field_name, combined); - return absl::Status(); -} - - -std::unordered_map* - ProtoStreamObjectSource::renderers_ = nullptr; -absl::once_flag source_renderers_init_; - - -void ProtoStreamObjectSource::InitRendererMap() { - renderers_ = new std::unordered_map(); - (*renderers_)["google.protobuf.Timestamp"] = - &ProtoStreamObjectSource::RenderTimestamp; - (*renderers_)["google.protobuf.Duration"] = - &ProtoStreamObjectSource::RenderDuration; - (*renderers_)["google.protobuf.DoubleValue"] = - &ProtoStreamObjectSource::RenderDouble; - (*renderers_)["google.protobuf.FloatValue"] = - &ProtoStreamObjectSource::RenderFloat; - (*renderers_)["google.protobuf.Int64Value"] = - &ProtoStreamObjectSource::RenderInt64; - (*renderers_)["google.protobuf.UInt64Value"] = - &ProtoStreamObjectSource::RenderUInt64; - (*renderers_)["google.protobuf.Int32Value"] = - &ProtoStreamObjectSource::RenderInt32; - (*renderers_)["google.protobuf.UInt32Value"] = - &ProtoStreamObjectSource::RenderUInt32; - (*renderers_)["google.protobuf.BoolValue"] = - &ProtoStreamObjectSource::RenderBool; - (*renderers_)["google.protobuf.StringValue"] = - &ProtoStreamObjectSource::RenderString; - (*renderers_)["google.protobuf.BytesValue"] = - &ProtoStreamObjectSource::RenderBytes; - (*renderers_)["google.protobuf.Any"] = &ProtoStreamObjectSource::RenderAny; - (*renderers_)["google.protobuf.Struct"] = - &ProtoStreamObjectSource::RenderStruct; - (*renderers_)["google.protobuf.Value"] = - &ProtoStreamObjectSource::RenderStructValue; - (*renderers_)["google.protobuf.ListValue"] = - &ProtoStreamObjectSource::RenderStructListValue; - (*renderers_)["google.protobuf.FieldMask"] = - &ProtoStreamObjectSource::RenderFieldMask; - ::google::protobuf::internal::OnShutdown(&DeleteRendererMap); -} - -void ProtoStreamObjectSource::DeleteRendererMap() { - delete ProtoStreamObjectSource::renderers_; - renderers_ = nullptr; -} - -// static -ProtoStreamObjectSource::TypeRenderer* -ProtoStreamObjectSource::FindTypeRenderer(const std::string& type_url) { - absl::call_once(source_renderers_init_, InitRendererMap); - auto it = renderers_->find(type_url); - if (it == renderers_->end()) return nullptr; - return &it->second; -} - -absl::Status ProtoStreamObjectSource::RenderField( - const google::protobuf::Field* field, absl::string_view field_name, - ObjectWriter* ow) const { - // Short-circuit message types as it tends to call WriteMessage recursively - // and ends up using a lot of stack space. Keep the stack usage of this - // message small in order to preserve stack space and not crash. - if (field->kind() == google::protobuf::Field::TYPE_MESSAGE) { - uint32_t buffer32; - stream_->ReadVarint32(&buffer32); // message length - int old_limit = stream_->PushLimit(buffer32); - // Get the nested message type for this field. - const google::protobuf::Type* type = - typeinfo_->GetTypeByTypeUrl(field->type_url()); - if (type == nullptr) { - return absl::InternalError( - absl::StrCat("Invalid configuration. Could not find the type: ", - field->type_url())); - } - - // Short-circuit any special type rendering to save call-stack space. - const TypeRenderer* type_renderer = FindTypeRenderer(type->name()); - - RETURN_IF_ERROR(IncrementRecursionDepth(type->name(), field_name)); - if (type_renderer != nullptr) { - RETURN_IF_ERROR((*type_renderer)(this, *type, field_name, ow)); - } else { - RETURN_IF_ERROR(WriteMessage(*type, field_name, 0, true, ow)); - } - --recursion_depth_; - - if (!stream_->ConsumedEntireMessage()) { - return absl::InvalidArgumentError( - "Nested protocol message not parsed in its entirety."); - } - stream_->PopLimit(old_limit); - } else { - // Render all other non-message types. - return RenderNonMessageField(field, field_name, ow); - } - return absl::Status(); -} - -absl::Status ProtoStreamObjectSource::RenderNonMessageField( - const google::protobuf::Field* field, absl::string_view field_name, - ObjectWriter* ow) const { - // Temporary buffers of different types. - uint32_t buffer32 = 0; - uint64_t buffer64 = 0; - std::string strbuffer; - switch (field->kind()) { - case google::protobuf::Field::TYPE_BOOL: { - stream_->ReadVarint64(&buffer64); - ow->RenderBool(field_name, buffer64 != 0); - break; - } - case google::protobuf::Field::TYPE_INT32: { - stream_->ReadVarint32(&buffer32); - ow->RenderInt32(field_name, absl::bit_cast(buffer32)); - break; - } - case google::protobuf::Field::TYPE_INT64: { - stream_->ReadVarint64(&buffer64); - ow->RenderInt64(field_name, absl::bit_cast(buffer64)); - break; - } - case google::protobuf::Field::TYPE_UINT32: { - stream_->ReadVarint32(&buffer32); - ow->RenderUint32(field_name, absl::bit_cast(buffer32)); - break; - } - case google::protobuf::Field::TYPE_UINT64: { - stream_->ReadVarint64(&buffer64); - ow->RenderUint64(field_name, absl::bit_cast(buffer64)); - break; - } - case google::protobuf::Field::TYPE_SINT32: { - stream_->ReadVarint32(&buffer32); - ow->RenderInt32(field_name, WireFormatLite::ZigZagDecode32(buffer32)); - break; - } - case google::protobuf::Field::TYPE_SINT64: { - stream_->ReadVarint64(&buffer64); - ow->RenderInt64(field_name, WireFormatLite::ZigZagDecode64(buffer64)); - break; - } - case google::protobuf::Field::TYPE_SFIXED32: { - stream_->ReadLittleEndian32(&buffer32); - ow->RenderInt32(field_name, absl::bit_cast(buffer32)); - break; - } - case google::protobuf::Field::TYPE_SFIXED64: { - stream_->ReadLittleEndian64(&buffer64); - ow->RenderInt64(field_name, absl::bit_cast(buffer64)); - break; - } - case google::protobuf::Field::TYPE_FIXED32: { - stream_->ReadLittleEndian32(&buffer32); - ow->RenderUint32(field_name, absl::bit_cast(buffer32)); - break; - } - case google::protobuf::Field::TYPE_FIXED64: { - stream_->ReadLittleEndian64(&buffer64); - ow->RenderUint64(field_name, absl::bit_cast(buffer64)); - break; - } - case google::protobuf::Field::TYPE_FLOAT: { - stream_->ReadLittleEndian32(&buffer32); - ow->RenderFloat(field_name, absl::bit_cast(buffer32)); - break; - } - case google::protobuf::Field::TYPE_DOUBLE: { - stream_->ReadLittleEndian64(&buffer64); - ow->RenderDouble(field_name, absl::bit_cast(buffer64)); - break; - } - case google::protobuf::Field::TYPE_ENUM: { - stream_->ReadVarint32(&buffer32); - - // If the field represents an explicit NULL value, render null. - if (field->type_url() == kStructNullValueTypeUrl) { - ow->RenderNull(field_name); - break; - } - - // Get the nested enum type for this field. - // TODO(skarvaje): Avoid string manipulation. Find ways to speed this - // up. - const google::protobuf::Enum* en = - typeinfo_->GetEnumByTypeUrl(field->type_url()); - // Lookup the name of the enum, and render that. Unknown enum values - // are printed as integers. - if (en != nullptr) { - const google::protobuf::EnumValue* enum_value = - FindEnumValueByNumber(*en, buffer32); - if (enum_value != nullptr) { - if (render_options_.use_ints_for_enums) { - ow->RenderInt32(field_name, buffer32); - } else if (render_options_.use_lower_camel_for_enums) { - ow->RenderString(field_name, - EnumValueNameToLowerCamelCase(enum_value->name())); - } else { - ow->RenderString(field_name, enum_value->name()); - } - } else { - ow->RenderInt32(field_name, buffer32); - } - } else { - ow->RenderInt32(field_name, buffer32); - } - break; - } - case google::protobuf::Field::TYPE_STRING: { - stream_->ReadVarint32(&buffer32); // string size. - stream_->ReadString(&strbuffer, buffer32); - ow->RenderString(field_name, strbuffer); - break; - } - case google::protobuf::Field::TYPE_BYTES: { - stream_->ReadVarint32(&buffer32); // bytes size. - stream_->ReadString(&strbuffer, buffer32); - ow->RenderBytes(field_name, strbuffer); - break; - } - default: - break; - } - return absl::Status(); -} - -// TODO(skarvaje): Fix this to avoid code duplication. -std::string ProtoStreamObjectSource::ReadFieldValueAsString( - const google::protobuf::Field& field) const { - std::string result; - switch (field.kind()) { - case google::protobuf::Field::TYPE_BOOL: { - uint64_t buffer64; - stream_->ReadVarint64(&buffer64); - result = buffer64 != 0 ? "true" : "false"; - break; - } - case google::protobuf::Field::TYPE_INT32: { - uint32_t buffer32; - stream_->ReadVarint32(&buffer32); - result = absl::StrCat(absl::bit_cast(buffer32)); - break; - } - case google::protobuf::Field::TYPE_INT64: { - uint64_t buffer64; - stream_->ReadVarint64(&buffer64); - result = absl::StrCat(absl::bit_cast(buffer64)); - break; - } - case google::protobuf::Field::TYPE_UINT32: { - uint32_t buffer32; - stream_->ReadVarint32(&buffer32); - result = absl::StrCat(absl::bit_cast(buffer32)); - break; - } - case google::protobuf::Field::TYPE_UINT64: { - uint64_t buffer64; - stream_->ReadVarint64(&buffer64); - result = absl::StrCat(absl::bit_cast(buffer64)); - break; - } - case google::protobuf::Field::TYPE_SINT32: { - uint32_t buffer32; - stream_->ReadVarint32(&buffer32); - result = absl::StrCat(WireFormatLite::ZigZagDecode32(buffer32)); - break; - } - case google::protobuf::Field::TYPE_SINT64: { - uint64_t buffer64; - stream_->ReadVarint64(&buffer64); - result = absl::StrCat(WireFormatLite::ZigZagDecode64(buffer64)); - break; - } - case google::protobuf::Field::TYPE_SFIXED32: { - uint32_t buffer32; - stream_->ReadLittleEndian32(&buffer32); - result = absl::StrCat(absl::bit_cast(buffer32)); - break; - } - case google::protobuf::Field::TYPE_SFIXED64: { - uint64_t buffer64; - stream_->ReadLittleEndian64(&buffer64); - result = absl::StrCat(absl::bit_cast(buffer64)); - break; - } - case google::protobuf::Field::TYPE_FIXED32: { - uint32_t buffer32; - stream_->ReadLittleEndian32(&buffer32); - result = absl::StrCat(absl::bit_cast(buffer32)); - break; - } - case google::protobuf::Field::TYPE_FIXED64: { - uint64_t buffer64; - stream_->ReadLittleEndian64(&buffer64); - result = absl::StrCat(absl::bit_cast(buffer64)); - break; - } - case google::protobuf::Field::TYPE_FLOAT: { - uint32_t buffer32; - stream_->ReadLittleEndian32(&buffer32); - result = SimpleFtoa(absl::bit_cast(buffer32)); - break; - } - case google::protobuf::Field::TYPE_DOUBLE: { - uint64_t buffer64; - stream_->ReadLittleEndian64(&buffer64); - result = SimpleDtoa(absl::bit_cast(buffer64)); - break; - } - case google::protobuf::Field::TYPE_ENUM: { - uint32_t buffer32; - stream_->ReadVarint32(&buffer32); - // Get the nested enum type for this field. - // TODO(skarvaje): Avoid string manipulation. Find ways to speed this - // up. - const google::protobuf::Enum* en = - typeinfo_->GetEnumByTypeUrl(field.type_url()); - // Lookup the name of the enum, and render that. Skips unknown enums. - if (en != nullptr) { - const google::protobuf::EnumValue* enum_value = - FindEnumValueByNumber(*en, buffer32); - if (enum_value != nullptr) { - result = enum_value->name(); - } - } - break; - } - case google::protobuf::Field::TYPE_STRING: { - uint32_t buffer32; - stream_->ReadVarint32(&buffer32); // string size. - stream_->ReadString(&result, buffer32); - break; - } - case google::protobuf::Field::TYPE_BYTES: { - uint32_t buffer32; - stream_->ReadVarint32(&buffer32); // bytes size. - stream_->ReadString(&result, buffer32); - break; - } - default: - break; - } - return result; -} - -// Field is a map if it is a repeated message and it has an option "map_type". -// TODO(skarvaje): Consider pre-computing the IsMap() into Field directly. -bool ProtoStreamObjectSource::IsMap( - const google::protobuf::Field& field) const { - const google::protobuf::Type* field_type = - typeinfo_->GetTypeByTypeUrl(field.type_url()); - return field.kind() == google::protobuf::Field::TYPE_MESSAGE && - util::converter::IsMap(field, *field_type); -} - -std::pair ProtoStreamObjectSource::ReadSecondsAndNanos( - const google::protobuf::Type& type) const { - uint64_t seconds = 0; - uint32_t nanos = 0; - uint32_t tag = 0; - int64_t signed_seconds = 0; - int32_t signed_nanos = 0; - - for (tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) { - const google::protobuf::Field* field = FindAndVerifyField(type, tag); - if (field == nullptr) { - WireFormat::SkipField(stream_, tag, nullptr); - continue; - } - // 'seconds' has field number of 1 and 'nanos' has field number 2 - // //google/protobuf/timestamp.proto & duration.proto - if (field->number() == 1) { - // read seconds - stream_->ReadVarint64(&seconds); - signed_seconds = absl::bit_cast(seconds); - } else if (field->number() == 2) { - // read nanos - stream_->ReadVarint32(&nanos); - signed_nanos = absl::bit_cast(nanos); - } - } - return std::pair(signed_seconds, signed_nanos); -} - -absl::Status ProtoStreamObjectSource::IncrementRecursionDepth( - absl::string_view type_name, absl::string_view field_name) const { - if (++recursion_depth_ > max_recursion_depth_) { - return absl::InvalidArgumentError( - absl::StrCat("Message too deep. Max recursion depth reached for type '", - type_name, "', field '", field_name, "'")); - } - return absl::Status(); -} - -namespace { -// TODO(skarvaje): Speed this up by not doing a linear scan. -const google::protobuf::Field* FindFieldByNumber( - const google::protobuf::Type& type, int number) { - for (int i = 0; i < type.fields_size(); ++i) { - if (type.fields(i).number() == number) { - return &type.fields(i); - } - } - return nullptr; -} - -// TODO(skarvaje): Replace FieldDescriptor by implementing IsTypePackable() -// using tech Field. -bool IsPackable(const google::protobuf::Field& field) { - return field.cardinality() == google::protobuf::Field::CARDINALITY_REPEATED && - FieldDescriptor::IsTypePackable( - static_cast(field.kind())); -} - -// TODO(skarvaje): Speed this up by not doing a linear scan. -const google::protobuf::EnumValue* FindEnumValueByNumber( - const google::protobuf::Enum& tech_enum, int number) { - for (int i = 0; i < tech_enum.enumvalue_size(); ++i) { - const google::protobuf::EnumValue& ev = tech_enum.enumvalue(i); - if (ev.number() == number) { - return &ev; - } - } - return nullptr; -} - -// TODO(skarvaje): Look into optimizing this by not doing computation on -// double. -std::string FormatNanos(uint32_t nanos, bool with_trailing_zeros) { - if (nanos == 0) { - return with_trailing_zeros ? ".000" : ""; - } - - const int precision = (nanos % 1000 != 0) ? 9 - : (nanos % 1000000 != 0) ? 6 - : 3; - std::string formatted = absl::StrFormat( - "%.*f", precision, static_cast(nanos) / kNanosPerSecond); - // remove the leading 0 before decimal. - return formatted.substr(1); -} -} // namespace - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h deleted file mode 100644 index 350966b5ec..0000000000 --- a/src/google/protobuf/util/internal/protostream_objectsource.h +++ /dev/null @@ -1,325 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTSOURCE_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTSOURCE_H__ - -#include -#include -#include -#include - - -#include "google/protobuf/stubs/common.h" -#include "google/protobuf/type.pb.h" -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "google/protobuf/port.h" -#include "google/protobuf/util/internal/object_source.h" -#include "google/protobuf/util/internal/object_writer.h" -#include "google/protobuf/util/internal/type_info.h" -#include "google/protobuf/util/type_resolver.h" - - -// Must be included last. -#include "google/protobuf/port_def.inc" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -class TypeInfo; - -// An ObjectSource that can parse a stream of bytes as a protocol buffer. -// Its WriteTo() method can be given an ObjectWriter. -// This implementation uses a google.protobuf.Type for tag and name lookup. -// The field names are converted into lower camel-case when writing to the -// ObjectWriter. -// -// Sample usage: (suppose input is: string proto) -// ArrayInputStream arr_stream(proto.data(), proto.size()); -// CodedInputStream in_stream(&arr_stream); -// ProtoStreamObjectSource os(&in_stream, /*ServiceTypeInfo*/ typeinfo, -// ); -// -// Status status = os.WriteTo(); -class PROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { - public: - - struct RenderOptions { - // Sets whether or not to use lowerCamelCase casing for enum values. If set - // to false, enum values are output without any case conversions. - // - // For example, if we have an enum: - // enum Type { - // ACTION_AND_ADVENTURE = 1; - // } - // Type type = 20; - // - // And this option is set to true. Then the rendered "type" field will have - // the string "actionAndAdventure". - // { - // ... - // "type": "actionAndAdventure", - // ... - // } - // - // If set to false, the rendered "type" field will have the string - // "ACTION_AND_ADVENTURE". - // { - // ... - // "type": "ACTION_AND_ADVENTURE", - // ... - // } - bool use_lower_camel_for_enums = false; - - // Sets whether to always output enums as ints, by default this is off, and - // enums are rendered as strings. - bool use_ints_for_enums = false; - - // Whether to preserve proto field names - bool preserve_proto_field_names = false; - - }; - - ProtoStreamObjectSource(io::CodedInputStream* stream, - TypeResolver* type_resolver, - const google::protobuf::Type& type) - : ProtoStreamObjectSource(stream, type_resolver, type, RenderOptions()) {} - ProtoStreamObjectSource(io::CodedInputStream* stream, - TypeResolver* type_resolver, - const google::protobuf::Type& type, - const RenderOptions& render_options); - ProtoStreamObjectSource() = delete; - ProtoStreamObjectSource(const ProtoStreamObjectSource&) = delete; - ProtoStreamObjectSource& operator=(const ProtoStreamObjectSource&) = delete; - ~ProtoStreamObjectSource() override; - - absl::Status NamedWriteTo(absl::string_view name, - ObjectWriter* ow) const override; - - // Sets the max recursion depth of proto message to be deserialized. Proto - // messages over this depth will fail to be deserialized. - // Default value is 64. - void set_max_recursion_depth(int max_depth) { - max_recursion_depth_ = max_depth; - } - - protected: - // Writes a proto2 Message to the ObjectWriter. When the given end_tag is - // found this method will complete, allowing it to be used for parsing both - // nested messages (end with 0) and nested groups (end with group end tag). - // The include_start_and_end parameter allows this method to be called when - // already inside of an object, and skip calling StartObject and EndObject. - virtual absl::Status WriteMessage(const google::protobuf::Type& type, - absl::string_view name, - const uint32_t end_tag, - bool include_start_and_end, - ObjectWriter* ow) const; - - // Renders a repeating field (packed or unpacked). Returns the next tag after - // reading all sequential repeating elements. The caller should use this tag - // before reading more tags from the stream. - virtual absl::StatusOr RenderList( - const google::protobuf::Field* field, absl::string_view name, - uint32_t list_tag, ObjectWriter* ow) const; - - // Looks up a field and verify its consistency with wire type in tag. - const google::protobuf::Field* FindAndVerifyField( - const google::protobuf::Type& type, uint32_t tag) const; - - // Renders a field value to the ObjectWriter. - virtual absl::Status RenderField(const google::protobuf::Field* field, - absl::string_view field_name, - ObjectWriter* ow) const; - - // Reads field value according to Field spec in 'field' and returns the read - // value as string. This only works for primitive datatypes (no message - // types). - std::string ReadFieldValueAsString( - const google::protobuf::Field& field) const; - - - // Returns the input stream. - io::CodedInputStream* stream() const { return stream_; } - - private: - ProtoStreamObjectSource(io::CodedInputStream* stream, - const TypeInfo* typeinfo, - const google::protobuf::Type& type, - const RenderOptions& render_options); - // Function that renders a well known type with a modified behavior. - typedef absl::Status (*TypeRenderer)(const ProtoStreamObjectSource*, - const google::protobuf::Type&, - absl::string_view, ObjectWriter*); - - // TODO(skarvaje): Mark these methods as non-const as they modify internal - // state (stream_). - // - // Renders a NWP map. - // Returns the next tag after reading all map entries. The caller should use - // this tag before reading more tags from the stream. - absl::StatusOr RenderMap(const google::protobuf::Field* field, - absl::string_view name, uint32_t list_tag, - ObjectWriter* ow) const; - - // Renders a packed repeating field. A packed field is stored as: - // {tag length item1 item2 item3} instead of the less efficient - // {tag item1 tag item2 tag item3}. - absl::Status RenderPacked(const google::protobuf::Field* field, - ObjectWriter* ow) const; - - // Renders a google.protobuf.Timestamp value to ObjectWriter - static absl::Status RenderTimestamp(const ProtoStreamObjectSource* os, - const google::protobuf::Type& type, - absl::string_view name, ObjectWriter* ow); - - // Renders a google.protobuf.Duration value to ObjectWriter - static absl::Status RenderDuration(const ProtoStreamObjectSource* os, - const google::protobuf::Type& type, - absl::string_view name, ObjectWriter* ow); - - // Following RenderTYPE functions render well known types in - // google/protobuf/wrappers.proto corresponding to TYPE. - static absl::Status RenderDouble(const ProtoStreamObjectSource* os, - const google::protobuf::Type& type, - absl::string_view name, ObjectWriter* ow); - static absl::Status RenderFloat(const ProtoStreamObjectSource* os, - const google::protobuf::Type& type, - absl::string_view name, ObjectWriter* ow); - static absl::Status RenderInt64(const ProtoStreamObjectSource* os, - const google::protobuf::Type& type, - absl::string_view name, ObjectWriter* ow); - static absl::Status RenderUInt64(const ProtoStreamObjectSource* os, - const google::protobuf::Type& type, - absl::string_view name, ObjectWriter* ow); - static absl::Status RenderInt32(const ProtoStreamObjectSource* os, - const google::protobuf::Type& type, - absl::string_view name, ObjectWriter* ow); - static absl::Status RenderUInt32(const ProtoStreamObjectSource* os, - const google::protobuf::Type& type, - absl::string_view name, ObjectWriter* ow); - static absl::Status RenderBool(const ProtoStreamObjectSource* os, - const google::protobuf::Type& type, - absl::string_view name, ObjectWriter* ow); - static absl::Status RenderString(const ProtoStreamObjectSource* os, - const google::protobuf::Type& type, - absl::string_view name, ObjectWriter* ow); - static absl::Status RenderBytes(const ProtoStreamObjectSource* os, - const google::protobuf::Type& type, - absl::string_view name, ObjectWriter* ow); - - // Renders a google.protobuf.Struct to ObjectWriter. - static absl::Status RenderStruct(const ProtoStreamObjectSource* os, - const google::protobuf::Type& type, - absl::string_view name, ObjectWriter* ow); - - // Helper to render google.protobuf.Struct's Value fields to ObjectWriter. - static absl::Status RenderStructValue(const ProtoStreamObjectSource* os, - const google::protobuf::Type& type, - absl::string_view name, - ObjectWriter* ow); - - // Helper to render google.protobuf.Struct's ListValue fields to ObjectWriter. - static absl::Status RenderStructListValue(const ProtoStreamObjectSource* os, - const google::protobuf::Type& type, - absl::string_view name, - ObjectWriter* ow); - - // Render the "Any" type. - static absl::Status RenderAny(const ProtoStreamObjectSource* os, - const google::protobuf::Type& type, - absl::string_view name, ObjectWriter* ow); - - // Render the "FieldMask" type. - static absl::Status RenderFieldMask(const ProtoStreamObjectSource* os, - const google::protobuf::Type& type, - absl::string_view name, ObjectWriter* ow); - - static std::unordered_map* renderers_; - static void InitRendererMap(); - static void DeleteRendererMap(); - static TypeRenderer* FindTypeRenderer(const std::string& type_url); - - // Same as above but renders all non-message field types. Callers don't call - // this function directly. They just use RenderField. - absl::Status RenderNonMessageField(const google::protobuf::Field* field, - absl::string_view field_name, - ObjectWriter* ow) const; - - - // Utility function to detect proto maps. The 'field' MUST be repeated. - bool IsMap(const google::protobuf::Field& field) const; - - // Utility to read int64 and int32 values from a message type in stream_. - // Used for reading google.protobuf.Timestamp and Duration messages. - std::pair ReadSecondsAndNanos( - const google::protobuf::Type& type) const; - - // Helper function to check recursion depth and increment it. It will return - // OkStatus() if the current depth is allowed. Otherwise an error is returned. - // type_name and field_name are used for error reporting. - absl::Status IncrementRecursionDepth(absl::string_view type_name, - absl::string_view field_name) const; - - // Input stream to read from. Ownership rests with the caller. - mutable io::CodedInputStream* stream_; - - // Type information for all the types used in the descriptor. Used to find - // google::protobuf::Type of nested messages/enums. - const TypeInfo* typeinfo_; - - // Whether this class owns the typeinfo_ object. If true the typeinfo_ object - // should be deleted in the destructor. - bool own_typeinfo_; - - // google::protobuf::Type of the message source. - const google::protobuf::Type& type_; - - - const RenderOptions render_options_; - - // Tracks current recursion depth. - mutable int recursion_depth_; - - // Maximum allowed recursion depth. - int max_recursion_depth_; -}; - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google - -#include "google/protobuf/port_undef.inc" - -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTSOURCE_H__ diff --git a/src/google/protobuf/util/internal/protostream_objectsource_test.cc b/src/google/protobuf/util/internal/protostream_objectsource_test.cc deleted file mode 100644 index 4fde30b19f..0000000000 --- a/src/google/protobuf/util/internal/protostream_objectsource_test.cc +++ /dev/null @@ -1,1166 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google/protobuf/util/internal/protostream_objectsource.h" - -#include -#include -#include - -#include "google/protobuf/any.pb.h" -#include "google/protobuf/io/coded_stream.h" -#include "google/protobuf/io/zero_copy_stream_impl_lite.h" -#include "google/protobuf/descriptor.h" -#include "google/protobuf/util/internal/expecting_objectwriter.h" -#include -#include "absl/base/casts.h" -#include "absl/status/status.h" -#include "absl/strings/str_cat.h" -#include "google/protobuf/util/internal/constants.h" -#include "google/protobuf/util/internal/testdata/anys.pb.h" -#include "google/protobuf/util/internal/testdata/books.pb.h" -#include "google/protobuf/util/internal/testdata/field_mask.pb.h" -#include "google/protobuf/util/internal/testdata/maps.pb.h" -#include "google/protobuf/util/internal/testdata/proto3.pb.h" -#include "google/protobuf/util/internal/testdata/struct.pb.h" -#include "google/protobuf/util/internal/testdata/timestamp_duration.pb.h" -#include "google/protobuf/util/internal/type_info_test_helper.h" - - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -using ::google::protobuf::Any; -using io::ArrayInputStream; -using io::CodedInputStream; -using proto_util_converter::testing::AnyM; -using proto_util_converter::testing::AnyOut; -using proto_util_converter::testing::Author; -using proto_util_converter::testing::BadAuthor; -using proto_util_converter::testing::BadNestedBook; -using proto_util_converter::testing::Book; -using proto_util_converter::testing::Book_Label; -using proto_util_converter::testing::Cyclic; -using proto_util_converter::testing::FieldMaskTest; -using proto_util_converter::testing::MapOut; -using proto_util_converter::testing::MapOutWireFormat; -using proto_util_converter::testing::NestedBook; -using proto_util_converter::testing::NestedFieldMask; -using proto_util_converter::testing::PackedPrimitive; -using proto_util_converter::testing::Primitive; -using proto_util_converter::testing::Proto3Message; -using proto_util_converter::testing::StructType; -using proto_util_converter::testing::TimestampDuration; -using ::testing::_; - - -namespace { -std::string GetTypeUrl(const Descriptor* descriptor) { - return std::string(kTypeServiceBaseUrl) + "/" + descriptor->full_name(); -} -} // namespace - -class ProtostreamObjectSourceTest - : public ::testing::TestWithParam { - protected: - ProtostreamObjectSourceTest() - : helper_(GetParam()), - mock_(), - ow_(&mock_), - use_lower_camel_for_enums_(false), - use_ints_for_enums_(false), - use_preserve_proto_field_names_(false), - add_trailing_zeros_(false), - render_unknown_enum_values_(true) { - helper_.ResetTypeInfo(Book::descriptor(), Proto3Message::descriptor()); - } - - ~ProtostreamObjectSourceTest() override {} - - void DoTest(const Message& msg, const Descriptor* descriptor) { - absl::Status status = ExecuteTest(msg, descriptor); - EXPECT_EQ(absl::Status(), status); - } - - absl::Status ExecuteTest(const Message& msg, const Descriptor* descriptor) { - std::ostringstream oss; - msg.SerializePartialToOstream(&oss); - std::string proto = oss.str(); - ArrayInputStream arr_stream(proto.data(), proto.size()); - CodedInputStream in_stream(&arr_stream); - - ProtoStreamObjectSource::RenderOptions render_options; - render_options.use_lower_camel_for_enums = use_lower_camel_for_enums_; - render_options.use_ints_for_enums = use_ints_for_enums_; - render_options.preserve_proto_field_names = use_preserve_proto_field_names_; - std::unique_ptr os(helper_.NewProtoSource( - &in_stream, GetTypeUrl(descriptor), render_options)); - os->set_max_recursion_depth(64); - return os->WriteTo(&mock_); - } - - void PrepareExpectingObjectWriterForRepeatedPrimitive() { - ow_.StartObject("") - ->StartList("repFix32") - ->RenderUint32("", absl::bit_cast(3201)) - ->RenderUint32("", absl::bit_cast(0)) - ->RenderUint32("", absl::bit_cast(3202)) - ->EndList() - ->StartList("repU32") - ->RenderUint32("", absl::bit_cast(3203)) - ->RenderUint32("", absl::bit_cast(0)) - ->EndList() - ->StartList("repI32") - ->RenderInt32("", 0) - ->RenderInt32("", 3204) - ->RenderInt32("", 3205) - ->EndList() - ->StartList("repSf32") - ->RenderInt32("", 3206) - ->RenderInt32("", 0) - ->EndList() - ->StartList("repS32") - ->RenderInt32("", 0) - ->RenderInt32("", 3207) - ->RenderInt32("", 3208) - ->EndList() - ->StartList("repFix64") - ->RenderUint64("", absl::bit_cast(int64_t{6401})) - ->RenderUint64("", absl::bit_cast(int64_t{0})) - ->EndList() - ->StartList("repU64") - ->RenderUint64("", absl::bit_cast(int64_t{0})) - ->RenderUint64("", absl::bit_cast(int64_t{6402})) - ->RenderUint64("", absl::bit_cast(int64_t{6403})) - ->EndList() - ->StartList("repI64") - ->RenderInt64("", 6404L) - ->RenderInt64("", 0L) - ->EndList() - ->StartList("repSf64") - ->RenderInt64("", 0L) - ->RenderInt64("", 6405L) - ->RenderInt64("", 6406L) - ->EndList() - ->StartList("repS64") - ->RenderInt64("", 6407L) - ->RenderInt64("", 0L) - ->EndList() - ->StartList("repFloat") - ->RenderFloat("", 0.0f) - ->RenderFloat("", 32.1f) - ->RenderFloat("", 32.2f) - ->EndList() - ->StartList("repDouble") - ->RenderDouble("", 64.1L) - ->RenderDouble("", 0.0L) - ->EndList() - ->StartList("repBool") - ->RenderBool("", true) - ->RenderBool("", false) - ->EndList() - ->EndObject(); - } - - Primitive PrepareRepeatedPrimitive() { - Primitive primitive; - primitive.add_rep_fix32(3201); - primitive.add_rep_fix32(0); - primitive.add_rep_fix32(3202); - primitive.add_rep_u32(3203); - primitive.add_rep_u32(0); - primitive.add_rep_i32(0); - primitive.add_rep_i32(3204); - primitive.add_rep_i32(3205); - primitive.add_rep_sf32(3206); - primitive.add_rep_sf32(0); - primitive.add_rep_s32(0); - primitive.add_rep_s32(3207); - primitive.add_rep_s32(3208); - primitive.add_rep_fix64(6401L); - primitive.add_rep_fix64(0L); - primitive.add_rep_u64(0L); - primitive.add_rep_u64(6402L); - primitive.add_rep_u64(6403L); - primitive.add_rep_i64(6404L); - primitive.add_rep_i64(0L); - primitive.add_rep_sf64(0L); - primitive.add_rep_sf64(6405L); - primitive.add_rep_sf64(6406L); - primitive.add_rep_s64(6407L); - primitive.add_rep_s64(0L); - primitive.add_rep_float(0.0f); - primitive.add_rep_float(32.1f); - primitive.add_rep_float(32.2f); - primitive.add_rep_double(64.1L); - primitive.add_rep_double(0.0); - primitive.add_rep_bool(true); - primitive.add_rep_bool(false); - - PrepareExpectingObjectWriterForRepeatedPrimitive(); - return primitive; - } - - PackedPrimitive PreparePackedPrimitive() { - PackedPrimitive primitive; - primitive.add_rep_fix32(3201); - primitive.add_rep_fix32(0); - primitive.add_rep_fix32(3202); - primitive.add_rep_u32(3203); - primitive.add_rep_u32(0); - primitive.add_rep_i32(0); - primitive.add_rep_i32(3204); - primitive.add_rep_i32(3205); - primitive.add_rep_sf32(3206); - primitive.add_rep_sf32(0); - primitive.add_rep_s32(0); - primitive.add_rep_s32(3207); - primitive.add_rep_s32(3208); - primitive.add_rep_fix64(6401L); - primitive.add_rep_fix64(0L); - primitive.add_rep_u64(0L); - primitive.add_rep_u64(6402L); - primitive.add_rep_u64(6403L); - primitive.add_rep_i64(6404L); - primitive.add_rep_i64(0L); - primitive.add_rep_sf64(0L); - primitive.add_rep_sf64(6405L); - primitive.add_rep_sf64(6406L); - primitive.add_rep_s64(6407L); - primitive.add_rep_s64(0L); - primitive.add_rep_float(0.0f); - primitive.add_rep_float(32.1f); - primitive.add_rep_float(32.2f); - primitive.add_rep_double(64.1L); - primitive.add_rep_double(0.0); - primitive.add_rep_bool(true); - primitive.add_rep_bool(false); - - PrepareExpectingObjectWriterForRepeatedPrimitive(); - return primitive; - } - - void UseLowerCamelForEnums() { use_lower_camel_for_enums_ = true; } - - void UseIntsForEnums() { use_ints_for_enums_ = true; } - - void UsePreserveProtoFieldNames() { use_preserve_proto_field_names_ = true; } - - void AddTrailingZeros() { add_trailing_zeros_ = true; } - - void SetRenderUnknownEnumValues(bool value) { - render_unknown_enum_values_ = value; - } - - testing::TypeInfoTestHelper helper_; - - ::testing::NiceMock mock_; - ExpectingObjectWriter ow_; - bool use_lower_camel_for_enums_; - bool use_ints_for_enums_; - bool use_preserve_proto_field_names_; - bool add_trailing_zeros_; - bool render_unknown_enum_values_; -}; - -INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest, - ProtostreamObjectSourceTest, - ::testing::Values( - testing::USE_TYPE_RESOLVER)); - -TEST_P(ProtostreamObjectSourceTest, EmptyMessage) { - Book empty; - ow_.StartObject("")->EndObject(); - DoTest(empty, Book::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, Primitives) { - Primitive primitive; - primitive.set_fix32(3201); - primitive.set_u32(3202); - primitive.set_i32(3203); - primitive.set_sf32(3204); - primitive.set_s32(3205); - primitive.set_fix64(6401L); - primitive.set_u64(6402L); - primitive.set_i64(6403L); - primitive.set_sf64(6404L); - primitive.set_s64(6405L); - primitive.set_str("String Value"); - primitive.set_bytes("Some Bytes"); - primitive.set_float_(32.1f); - primitive.set_double_(64.1L); - primitive.set_bool_(true); - - ow_.StartObject("") - ->RenderUint32("fix32", absl::bit_cast(3201)) - ->RenderUint32("u32", absl::bit_cast(3202)) - ->RenderInt32("i32", 3203) - ->RenderInt32("sf32", 3204) - ->RenderInt32("s32", 3205) - ->RenderUint64("fix64", absl::bit_cast(int64_t{6401})) - ->RenderUint64("u64", absl::bit_cast(int64_t{6402})) - ->RenderInt64("i64", 6403L) - ->RenderInt64("sf64", 6404L) - ->RenderInt64("s64", 6405L) - ->RenderString("str", "String Value") - ->RenderBytes("bytes", "Some Bytes") - ->RenderFloat("float", 32.1f) - ->RenderDouble("double", 64.1L) - ->RenderBool("bool", true) - ->EndObject(); - DoTest(primitive, Primitive::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, RepeatingPrimitives) { - Primitive primitive = PrepareRepeatedPrimitive(); - primitive.add_rep_str("String One"); - primitive.add_rep_str("String Two"); - primitive.add_rep_bytes("Some Bytes"); - - ow_.StartList("repStr") - ->RenderString("", "String One") - ->RenderString("", "String Two") - ->EndList() - ->StartList("repBytes") - ->RenderBytes("", "Some Bytes") - ->EndList(); - DoTest(primitive, Primitive::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, CustomJsonName) { - Author author; - author.set_id(12345); - - ow_.StartObject("")->RenderUint64("@id", 12345)->EndObject(); - DoTest(author, Author::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, NestedMessage) { - Author* author = new Author(); - author->set_name("Tolstoy"); - Book book; - book.set_title("My Book"); - book.set_allocated_author(author); - - ow_.StartObject("") - ->RenderString("title", "My Book") - ->StartObject("author") - ->RenderString("name", "Tolstoy") - ->EndObject() - ->EndObject(); - DoTest(book, Book::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, RepeatingField) { - Author author; - author.set_alive(false); - author.set_name("john"); - author.add_pseudonym("phil"); - author.add_pseudonym("bob"); - - ow_.StartObject("") - ->RenderBool("alive", false) - ->RenderString("name", "john") - ->StartList("pseudonym") - ->RenderString("", "phil") - ->RenderString("", "bob") - ->EndList() - ->EndObject(); - DoTest(author, Author::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, PackedRepeatingFields) { - DoTest(PreparePackedPrimitive(), PackedPrimitive::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, NonPackedPackableFieldsActuallyPacked) { - // Protostream is packed, but parse with non-packed Primitive. - DoTest(PreparePackedPrimitive(), Primitive::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, PackedPackableFieldNotActuallyPacked) { - // Protostream is not packed, but parse with PackedPrimitive. - DoTest(PrepareRepeatedPrimitive(), PackedPrimitive::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, BadAuthor) { - Author author; - author.set_alive(false); - author.set_name("john"); - author.set_id(1234L); - author.add_pseudonym("phil"); - author.add_pseudonym("bob"); - - ow_.StartObject("") - ->StartList("alive") - ->RenderBool("", false) - ->EndList() - ->StartList("name") - ->RenderUint64("", static_cast('j')) - ->RenderUint64("", static_cast('o')) - ->RenderUint64("", static_cast('h')) - ->RenderUint64("", static_cast('n')) - ->EndList() - ->RenderString("pseudonym", "phil") - ->RenderString("pseudonym", "bob") - ->EndObject(); - // Protostream created with Author, but parsed with BadAuthor. - DoTest(author, BadAuthor::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, NestedBookToBadNestedBook) { - Book* book = new Book(); - book->set_length(250); - book->set_published(2014L); - NestedBook nested; - nested.set_allocated_book(book); - - ow_.StartObject("") - ->StartList("book") - ->RenderUint32("", 24) // tag for field length (3 << 3) - ->RenderUint32("", 250) - ->RenderUint32("", 32) // tag for field published (4 << 3) - ->RenderUint32("", 2014) - ->EndList() - ->EndObject(); - // Protostream created with NestedBook, but parsed with BadNestedBook. - DoTest(nested, BadNestedBook::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, BadNestedBookToNestedBook) { - BadNestedBook nested; - nested.add_book(1); - nested.add_book(2); - nested.add_book(3); - nested.add_book(4); - nested.add_book(5); - nested.add_book(6); - nested.add_book(7); - - ow_.StartObject("")->StartObject("book")->EndObject()->EndObject(); - // Protostream created with BadNestedBook, but parsed with NestedBook. - DoTest(nested, NestedBook::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, - LongRepeatedListDoesNotBreakIntoMultipleJsonLists) { - Book book; - - int repeat = 10000; - for (int i = 0; i < repeat; ++i) { - Book_Label* label = book.add_labels(); - label->set_key(absl::StrCat("i", i)); - label->set_value(absl::StrCat("v", i)); - } - - // Make sure StartList and EndList are called exactly once (see b/18227499 for - // problems when this doesn't happen) - EXPECT_CALL(mock_, StartList(_)).Times(1); - EXPECT_CALL(mock_, EndList()).Times(1); - - DoTest(book, Book::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputMacroCase) { - Book book; - book.set_type(Book::ACTION_AND_ADVENTURE); - - UseLowerCamelForEnums(); - - ow_.StartObject("")->RenderString("type", "actionAndAdventure")->EndObject(); - DoTest(book, Book::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputSnakeCase) { - Book book; - book.set_type(Book::arts_and_photography); - - UseLowerCamelForEnums(); - - ow_.StartObject("")->RenderString("type", "artsAndPhotography")->EndObject(); - DoTest(book, Book::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputWithNumber) { - Book book; - book.set_type(Book::I18N_Tech); - - UseLowerCamelForEnums(); - - ow_.StartObject("")->RenderString("type", "i18nTech")->EndObject(); - DoTest(book, Book::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, EnumCaseIsUnchangedByDefault) { - Book book; - book.set_type(Book::ACTION_AND_ADVENTURE); - ow_.StartObject("") - ->RenderString("type", "ACTION_AND_ADVENTURE") - ->EndObject(); - DoTest(book, Book::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, UseIntsForEnumsTest) { - Book book; - book.set_type(Book::ACTION_AND_ADVENTURE); - - UseIntsForEnums(); - - ow_.StartObject("")->RenderInt32("type", 3)->EndObject(); - DoTest(book, Book::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, UsePreserveProtoFieldNames) { - Book book; - book.set_snake_field("foo"); - - UsePreserveProtoFieldNames(); - - ow_.StartObject("")->RenderString("snake_field", "foo")->EndObject(); - DoTest(book, Book::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, - UnknownEnumAreDroppedWhenRenderUnknownEnumValuesIsUnset) { - Proto3Message message; - message.set_enum_value(static_cast(1234)); - - SetRenderUnknownEnumValues(false); - - // Unknown enum values are not output. - ow_.StartObject("")->EndObject(); - DoTest(message, Proto3Message::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, - UnknownEnumAreOutputWhenRenderUnknownEnumValuesIsSet) { - Proto3Message message; - message.set_enum_value(static_cast(1234)); - - SetRenderUnknownEnumValues(true); - - // Unknown enum values are output. - ow_.StartObject("")->RenderInt32("enumValue", 1234)->EndObject(); - DoTest(message, Proto3Message::descriptor()); -} - -TEST_P(ProtostreamObjectSourceTest, CyclicMessageDepthTest) { - Cyclic cyclic; - cyclic.set_m_int(123); - - Book* book = cyclic.mutable_m_book(); - book->set_title("book title"); - Cyclic* current = cyclic.mutable_m_cyclic(); - Author* current_author = cyclic.add_m_author(); - for (int i = 0; i < 63; ++i) { - Author* next = current_author->add_friend_(); - next->set_id(i); - next->set_name(absl::StrCat("author_name_", i)); - next->set_alive(true); - current_author = next; - } - - // Recursive message with depth (65) > max (max is 64). - for (int i = 0; i < 64; ++i) { - Cyclic* next = current->mutable_m_cyclic(); - next->set_m_str(absl::StrCat("count_", i)); - current = next; - } - - absl::Status status = ExecuteTest(cyclic, Cyclic::descriptor()); - EXPECT_TRUE(absl::IsInvalidArgument(status)); -} - -class ProtostreamObjectSourceMapsTest : public ProtostreamObjectSourceTest { - protected: - ProtostreamObjectSourceMapsTest() { - helper_.ResetTypeInfo(MapOut::descriptor()); - } -}; - -INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest, - ProtostreamObjectSourceMapsTest, - ::testing::Values( - testing::USE_TYPE_RESOLVER)); - -// Tests JSON map. -// -// This is the example expected output. -// { -// "map1": { -// "key1": { -// "foo": "foovalue" -// }, -// "key2": { -// "foo": "barvalue" -// } -// }, -// "map2": { -// "nestedself": { -// "map1": { -// "nested_key1": { -// "foo": "nested_foo" -// } -// }, -// "bar": "nested_bar_string" -// } -// }, -// "map3": { -// "111": "one one one" -// }, -// "bar": "top bar" -// } -TEST_P(ProtostreamObjectSourceMapsTest, MapsTest) { - MapOut out; - (*out.mutable_map1())["key1"].set_foo("foovalue"); - (*out.mutable_map1())["key2"].set_foo("barvalue"); - - MapOut* nested_value = &(*out.mutable_map2())["nestedself"]; - (*nested_value->mutable_map1())["nested_key1"].set_foo("nested_foo"); - nested_value->set_bar("nested_bar_string"); - - (*out.mutable_map3())[111] = "one one one"; - - out.set_bar("top bar"); - - ow_.StartObject("") - ->StartObject("map1") - ->StartObject("key1") - ->RenderString("foo", "foovalue") - ->EndObject() - ->StartObject("key2") - ->RenderString("foo", "barvalue") - ->EndObject() - ->StartObject("map2") - ->StartObject("nestedself") - ->StartObject("map1") - ->StartObject("nested_key1") - ->RenderString("foo", "nested_foo") - ->EndObject() - ->EndObject() - ->RenderString("bar", "nested_bar_string") - ->EndObject() - ->EndObject() - ->StartObject("map3") - ->RenderString("111", "one one one") - ->EndObject() - ->EndObject() - ->RenderString("bar", "top bar") - ->EndObject(); - - DoTest(out, MapOut::descriptor()); -} - -TEST_P(ProtostreamObjectSourceMapsTest, MissingKeysTest) { - // MapOutWireFormat has the same wire representation with MapOut but uses - // repeated message fields to represent map fields so we can intentionally - // leave out the key field or the value field of a map entry. - MapOutWireFormat out; - // Create some map entries without keys. They will be rendered with the - // default values ("" for strings, "0" for integers, etc.). - // { - // "map1": { - // "": { - // "foo": "foovalue" - // } - // }, - // "map2": { - // "": { - // "map1": { - // "nested_key1": { - // "foo": "nested_foo" - // } - // } - // } - // }, - // "map3": { - // "0": "one one one" - // }, - // "map4": { - // "false": "bool" - // } - // } - out.add_map1()->mutable_value()->set_foo("foovalue"); - MapOut* nested = out.add_map2()->mutable_value(); - (*nested->mutable_map1())["nested_key1"].set_foo("nested_foo"); - out.add_map3()->set_value("one one one"); - out.add_map4()->set_value("bool"); - - ow_.StartObject("") - ->StartObject("map1") - ->StartObject("") - ->RenderString("foo", "foovalue") - ->EndObject() - ->EndObject() - ->StartObject("map2") - ->StartObject("") - ->StartObject("map1") - ->StartObject("nested_key1") - ->RenderString("foo", "nested_foo") - ->EndObject() - ->EndObject() - ->EndObject() - ->EndObject() - ->StartObject("map3") - ->RenderString("0", "one one one") - ->EndObject() - ->StartObject("map4") - ->RenderString("false", "bool") - ->EndObject() - ->EndObject(); - - DoTest(out, MapOut::descriptor()); -} - -class ProtostreamObjectSourceAnysTest : public ProtostreamObjectSourceTest { - protected: - ProtostreamObjectSourceAnysTest() { - helper_.ResetTypeInfo({AnyOut::descriptor(), Book::descriptor(), - google::protobuf::Any::descriptor()}); - } -}; - -INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest, - ProtostreamObjectSourceAnysTest, - ::testing::Values( - testing::USE_TYPE_RESOLVER)); - -// Tests JSON any support. -// -// This is the example expected output. -// { -// "any": { -// "@type": "type.googleapis.com/google.protobuf.testing.AnyM" -// "foo": "foovalue" -// } -// } -TEST_P(ProtostreamObjectSourceAnysTest, BasicAny) { - AnyOut out; - ::google::protobuf::Any* any = out.mutable_any(); - - AnyM m; - m.set_foo("foovalue"); - any->PackFrom(m); - - ow_.StartObject("") - ->StartObject("any") - ->RenderString("@type", - "type.googleapis.com/proto_util_converter.testing.AnyM") - ->RenderString("foo", "foovalue") - ->EndObject() - ->EndObject(); - - DoTest(out, AnyOut::descriptor()); -} - -TEST_P(ProtostreamObjectSourceAnysTest, LowerCamelEnumOutputSnakeCase) { - AnyOut out; - ::google::protobuf::Any* any = out.mutable_any(); - - Book book; - book.set_type(Book::arts_and_photography); - any->PackFrom(book); - - UseLowerCamelForEnums(); - - ow_.StartObject("") - ->StartObject("any") - ->RenderString("@type", - "type.googleapis.com/proto_util_converter.testing.Book") - ->RenderString("type", "artsAndPhotography") - ->EndObject() - ->EndObject(); - - DoTest(out, AnyOut::descriptor()); -} - -TEST_P(ProtostreamObjectSourceAnysTest, UseIntsForEnumsTest) { - AnyOut out; - ::google::protobuf::Any* any = out.mutable_any(); - - Book book; - book.set_type(Book::ACTION_AND_ADVENTURE); - any->PackFrom(book); - - UseIntsForEnums(); - - ow_.StartObject("") - ->StartObject("any") - ->RenderString("@type", - "type.googleapis.com/proto_util_converter.testing.Book") - ->RenderInt32("type", 3) - ->EndObject() - ->EndObject(); - - DoTest(out, AnyOut::descriptor()); -} - -TEST_P(ProtostreamObjectSourceAnysTest, UsePreserveProtoFieldNames) { - AnyOut out; - ::google::protobuf::Any* any = out.mutable_any(); - - Book book; - book.set_snake_field("foo"); - any->PackFrom(book); - - UsePreserveProtoFieldNames(); - - ow_.StartObject("") - ->StartObject("any") - ->RenderString("@type", - "type.googleapis.com/proto_util_converter.testing.Book") - ->RenderString("snake_field", "foo") - ->EndObject() - ->EndObject(); - - DoTest(out, AnyOut::descriptor()); -} - -TEST_P(ProtostreamObjectSourceAnysTest, RecursiveAny) { - AnyOut out; - ::google::protobuf::Any* any = out.mutable_any(); - any->set_type_url("type.googleapis.com/google.protobuf.Any"); - - ::google::protobuf::Any nested_any; - nested_any.set_type_url( - "type.googleapis.com/proto_util_converter.testing.AnyM"); - - AnyM m; - m.set_foo("foovalue"); - nested_any.set_value(m.SerializeAsString()); - - any->set_value(nested_any.SerializeAsString()); - - ow_.StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") - ->StartObject("value") - ->RenderString("@type", - "type.googleapis.com/proto_util_converter.testing.AnyM") - ->RenderString("foo", "foovalue") - ->EndObject() - ->EndObject() - ->EndObject(); - - DoTest(out, AnyOut::descriptor()); -} - -TEST_P(ProtostreamObjectSourceAnysTest, DoubleRecursiveAny) { - AnyOut out; - ::google::protobuf::Any* any = out.mutable_any(); - any->set_type_url("type.googleapis.com/google.protobuf.Any"); - - ::google::protobuf::Any nested_any; - nested_any.set_type_url("type.googleapis.com/google.protobuf.Any"); - - ::google::protobuf::Any second_nested_any; - second_nested_any.set_type_url( - "type.googleapis.com/proto_util_converter.testing.AnyM"); - - AnyM m; - m.set_foo("foovalue"); - second_nested_any.set_value(m.SerializeAsString()); - nested_any.set_value(second_nested_any.SerializeAsString()); - any->set_value(nested_any.SerializeAsString()); - - ow_.StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") - ->StartObject("value") - ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") - ->StartObject("value") - ->RenderString("@type", - "type.googleapis.com/proto_util_converter.testing.AnyM") - ->RenderString("foo", "foovalue") - ->EndObject() - ->EndObject() - ->EndObject() - ->EndObject(); - - DoTest(out, AnyOut::descriptor()); -} - -TEST_P(ProtostreamObjectSourceAnysTest, EmptyAnyOutputsEmptyObject) { - AnyOut out; - out.mutable_any(); - - ow_.StartObject("")->StartObject("any")->EndObject()->EndObject(); - - DoTest(out, AnyOut::descriptor()); -} - -TEST_P(ProtostreamObjectSourceAnysTest, EmptyWithTypeAndNoValueOutputsType) { - AnyOut out; - out.mutable_any()->set_type_url("foo.googleapis.com/my.Type"); - - ow_.StartObject("") - ->StartObject("any") - ->RenderString("@type", "foo.googleapis.com/my.Type") - ->EndObject() - ->EndObject(); - - DoTest(out, AnyOut::descriptor()); -} - -TEST_P(ProtostreamObjectSourceAnysTest, MissingTypeUrlError) { - AnyOut out; - ::google::protobuf::Any* any = out.mutable_any(); - - AnyM m; - m.set_foo("foovalue"); - any->set_value(m.SerializeAsString()); - - // We start the "AnyOut" part and then fail when we hit the Any object. - ow_.StartObject(""); - - absl::Status status = ExecuteTest(out, AnyOut::descriptor()); - EXPECT_TRUE(absl::IsInternal(status)); -} - -TEST_P(ProtostreamObjectSourceAnysTest, UnknownTypeServiceError) { - AnyOut out; - ::google::protobuf::Any* any = out.mutable_any(); - any->set_type_url("foo.googleapis.com/my.own.Type"); - - AnyM m; - m.set_foo("foovalue"); - any->set_value(m.SerializeAsString()); - - // We start the "AnyOut" part and then fail when we hit the Any object. - ow_.StartObject(""); - - absl::Status status = ExecuteTest(out, AnyOut::descriptor()); - EXPECT_TRUE(absl::IsInternal(status)); -} - -TEST_P(ProtostreamObjectSourceAnysTest, UnknownTypeError) { - AnyOut out; - ::google::protobuf::Any* any = out.mutable_any(); - any->set_type_url("type.googleapis.com/unknown.Type"); - - AnyM m; - m.set_foo("foovalue"); - any->set_value(m.SerializeAsString()); - - // We start the "AnyOut" part and then fail when we hit the Any object. - ow_.StartObject(""); - - absl::Status status = ExecuteTest(out, AnyOut::descriptor()); - EXPECT_TRUE(absl::IsInternal(status)); -} - -class ProtostreamObjectSourceStructTest : public ProtostreamObjectSourceTest { - protected: - ProtostreamObjectSourceStructTest() { - helper_.ResetTypeInfo(StructType::descriptor(), - google::protobuf::Struct::descriptor()); - } -}; - -INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest, - ProtostreamObjectSourceStructTest, - ::testing::Values( - testing::USE_TYPE_RESOLVER)); - -// Tests struct -// -// "object": { -// "k1": 123, -// "k2": true -// } -TEST_P(ProtostreamObjectSourceStructTest, StructRenderSuccess) { - StructType out; - google::protobuf::Struct* s = out.mutable_object(); - s->mutable_fields()->operator[]("k1").set_number_value(123); - s->mutable_fields()->operator[]("k2").set_bool_value(true); - - ow_.StartObject("") - ->StartObject("object") - ->RenderDouble("k1", 123) - ->RenderBool("k2", true) - ->EndObject() - ->EndObject(); - - DoTest(out, StructType::descriptor()); -} - -TEST_P(ProtostreamObjectSourceStructTest, MissingValueSkipsField) { - StructType out; - google::protobuf::Struct* s = out.mutable_object(); - s->mutable_fields()->operator[]("k1"); - - ow_.StartObject("")->StartObject("object")->EndObject()->EndObject(); - - DoTest(out, StructType::descriptor()); -} - -class ProtostreamObjectSourceFieldMaskTest - : public ProtostreamObjectSourceTest { - protected: - ProtostreamObjectSourceFieldMaskTest() { - helper_.ResetTypeInfo(FieldMaskTest::descriptor(), - google::protobuf::FieldMask::descriptor()); - } -}; - -INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest, - ProtostreamObjectSourceFieldMaskTest, - ::testing::Values( - testing::USE_TYPE_RESOLVER)); - -TEST_P(ProtostreamObjectSourceFieldMaskTest, FieldMaskRenderSuccess) { - FieldMaskTest out; - out.set_id("1"); - out.mutable_single_mask()->add_paths("path1"); - out.mutable_single_mask()->add_paths("snake_case_path2"); - ::google::protobuf::FieldMask* mask = out.add_repeated_mask(); - mask->add_paths("path3"); - mask = out.add_repeated_mask(); - mask->add_paths("snake_case_path4"); - mask->add_paths("path5"); - NestedFieldMask* nested = out.add_nested_mask(); - nested->set_data("data"); - nested->mutable_single_mask()->add_paths("nested.path1"); - nested->mutable_single_mask()->add_paths("nested_field.snake_case_path2"); - mask = nested->add_repeated_mask(); - mask->add_paths("nested_field.path3"); - mask->add_paths("nested.snake_case_path4"); - mask = nested->add_repeated_mask(); - mask->add_paths("nested.path5"); - mask = nested->add_repeated_mask(); - mask->add_paths( - "snake_case.map_field[\"map_key_should_be_ignored\"].nested_snake_case." - "map_field[\"map_key_sho\\\"uld_be_ignored\"]"); - - ow_.StartObject("") - ->RenderString("id", "1") - ->RenderString("singleMask", "path1,snakeCasePath2") - ->StartList("repeatedMask") - ->RenderString("", "path3") - ->RenderString("", "snakeCasePath4,path5") - ->EndList() - ->StartList("nestedMask") - ->StartObject("") - ->RenderString("data", "data") - ->RenderString("singleMask", "nested.path1,nestedField.snakeCasePath2") - ->StartList("repeatedMask") - ->RenderString("", "nestedField.path3,nested.snakeCasePath4") - ->RenderString("", "nested.path5") - ->RenderString("", - "snakeCase.mapField[\"map_key_should_be_ignored\"]." - "nestedSnakeCase.mapField[\"map_key_sho\\\"uld_be_" - "ignored\"]") - ->EndList() - ->EndObject() - ->EndList() - ->EndObject(); - - DoTest(out, FieldMaskTest::descriptor()); -} - -class ProtostreamObjectSourceTimestampTest - : public ProtostreamObjectSourceTest { - protected: - ProtostreamObjectSourceTimestampTest() { - helper_.ResetTypeInfo(TimestampDuration::descriptor()); - } -}; - -INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest, - ProtostreamObjectSourceTimestampTest, - ::testing::Values( - testing::USE_TYPE_RESOLVER)); - -TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampBelowMinTest) { - TimestampDuration out; - google::protobuf::Timestamp* ts = out.mutable_ts(); - // Min allowed seconds - 1 - ts->set_seconds(kTimestampMinSeconds - 1); - ow_.StartObject(""); - - absl::Status status = ExecuteTest(out, TimestampDuration::descriptor()); - EXPECT_TRUE(absl::IsInternal(status)); -} - -TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampAboveMaxTest) { - TimestampDuration out; - google::protobuf::Timestamp* ts = out.mutable_ts(); - // Max allowed seconds + 1 - ts->set_seconds(kTimestampMaxSeconds + 1); - ow_.StartObject(""); - - absl::Status status = ExecuteTest(out, TimestampDuration::descriptor()); - EXPECT_TRUE(absl::IsInternal(status)); -} - -TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationBelowMinTest) { - TimestampDuration out; - google::protobuf::Duration* dur = out.mutable_dur(); - // Min allowed seconds - 1 - dur->set_seconds(kDurationMinSeconds - 1); - ow_.StartObject(""); - - absl::Status status = ExecuteTest(out, TimestampDuration::descriptor()); - EXPECT_TRUE(absl::IsInternal(status)); -} - -TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationAboveMaxTest) { - TimestampDuration out; - google::protobuf::Duration* dur = out.mutable_dur(); - // Min allowed seconds + 1 - dur->set_seconds(kDurationMaxSeconds + 1); - ow_.StartObject(""); - - absl::Status status = ExecuteTest(out, TimestampDuration::descriptor()); - EXPECT_TRUE(absl::IsInternal(status)); -} - -TEST_P(ProtostreamObjectSourceTimestampTest, TimestampDurationDefaultValue) { - TimestampDuration out; - out.mutable_ts()->set_seconds(0); - out.mutable_dur()->set_seconds(0); - - ow_.StartObject("") - ->RenderString("ts", "1970-01-01T00:00:00Z") - ->RenderString("dur", "0s") - ->EndObject(); - - DoTest(out, TimestampDuration::descriptor()); -} - - - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc deleted file mode 100644 index 2c4d5ef575..0000000000 --- a/src/google/protobuf/util/internal/protostream_objectwriter.cc +++ /dev/null @@ -1,1447 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google/protobuf/util/internal/protostream_objectwriter.h" - -#include -#include -#include -#include -#include - -#include "google/protobuf/wire_format_lite.h" -#include "google/protobuf/stubs/strutil.h" -#include "absl/base/call_once.h" -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/match.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/strip.h" -#include "absl/time/time.h" -#include "google/protobuf/util/internal/constants.h" -#include "google/protobuf/util/internal/field_mask_utility.h" -#include "google/protobuf/util/internal/object_location_tracker.h" -#include "google/protobuf/util/internal/utility.h" - - -// Must be included last. -#include "google/protobuf/port_def.inc" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -using ::absl::Status; -using ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite; -using std::placeholders::_1; - - -ProtoStreamObjectWriter::ProtoStreamObjectWriter( - TypeResolver* type_resolver, const google::protobuf::Type& type, - strings::ByteSink* output, ErrorListener* listener, - const ProtoStreamObjectWriter::Options& options) - : ProtoWriter(type_resolver, type, output, listener), - master_type_(type), - current_(nullptr), - options_(options) { - set_ignore_unknown_fields(options_.ignore_unknown_fields); - set_ignore_unknown_enum_values(options_.ignore_unknown_enum_values); - set_use_lower_camel_for_enums(options_.use_lower_camel_for_enums); - set_case_insensitive_enum_parsing(options_.case_insensitive_enum_parsing); - set_use_json_name_in_missing_fields(options.use_json_name_in_missing_fields); -} - -ProtoStreamObjectWriter::ProtoStreamObjectWriter( - const TypeInfo* typeinfo, const google::protobuf::Type& type, - strings::ByteSink* output, ErrorListener* listener, - const ProtoStreamObjectWriter::Options& options) - : ProtoWriter(typeinfo, type, output, listener), - master_type_(type), - current_(nullptr), - options_(options) { - set_ignore_unknown_fields(options_.ignore_unknown_fields); - set_use_lower_camel_for_enums(options.use_lower_camel_for_enums); - set_case_insensitive_enum_parsing(options_.case_insensitive_enum_parsing); - set_use_json_name_in_missing_fields(options.use_json_name_in_missing_fields); -} - -ProtoStreamObjectWriter::ProtoStreamObjectWriter( - const TypeInfo* typeinfo, const google::protobuf::Type& type, - strings::ByteSink* output, ErrorListener* listener) - : ProtoWriter(typeinfo, type, output, listener), - master_type_(type), - current_(nullptr), - options_(ProtoStreamObjectWriter::Options::Defaults()) {} - -ProtoStreamObjectWriter::~ProtoStreamObjectWriter() { - if (current_ == nullptr) return; - // Cleanup explicitly in order to avoid destructor stack overflow when input - // is deeply nested. - // Cast to BaseElement to avoid doing additional checks (like missing fields) - // during pop(). - std::unique_ptr element( - static_cast(current_.get())->pop()); - while (element != nullptr) { - element.reset(element->pop()); - } -} - -namespace { -// Utility method to split a string representation of Timestamp or Duration and -// return the parts. -void SplitSecondsAndNanos(absl::string_view input, absl::string_view* seconds, - absl::string_view* nanos) { - size_t idx = input.rfind('.'); - if (idx != std::string::npos) { - *seconds = input.substr(0, idx); - *nanos = input.substr(idx + 1); - } else { - *seconds = input; - *nanos = absl::string_view(); - } -} - -Status GetNanosFromStringPiece(absl::string_view s_nanos, - const char* parse_failure_message, - const char* exceeded_limit_message, - int32_t* nanos) { - *nanos = 0; - - // Count the number of leading 0s and consume them. - int num_leading_zeros = 0; - while (absl::ConsumePrefix(&s_nanos, "0")) { - num_leading_zeros++; - } - int32_t i_nanos = 0; - // 's_nanos' contains fractional seconds -- i.e. 'nanos' is equal to - // "0." + s_nanos.ToString() seconds. An int32_t is used for the - // conversion to 'nanos', rather than a double, so that there is no - // loss of precision. - if (!s_nanos.empty() && !safe_strto32(s_nanos, &i_nanos)) { - return absl::InvalidArgumentError(parse_failure_message); - } - if (i_nanos > kNanosPerSecond || i_nanos < 0) { - return absl::InvalidArgumentError(exceeded_limit_message); - } - // s_nanos should only have digits. No whitespace. - if (s_nanos.find_first_not_of("0123456789") != absl::string_view::npos) { - return absl::InvalidArgumentError(parse_failure_message); - } - - if (i_nanos > 0) { - // 'scale' is the number of digits to the right of the decimal - // point in "0." + s_nanos.ToString() - int32_t scale = num_leading_zeros + s_nanos.size(); - // 'conversion' converts i_nanos into nanoseconds. - // conversion = kNanosPerSecond / static_cast(std::pow(10, scale)) - // For efficiency, we precompute the conversion factor. - int32_t conversion = 0; - switch (scale) { - case 1: - conversion = 100000000; - break; - case 2: - conversion = 10000000; - break; - case 3: - conversion = 1000000; - break; - case 4: - conversion = 100000; - break; - case 5: - conversion = 10000; - break; - case 6: - conversion = 1000; - break; - case 7: - conversion = 100; - break; - case 8: - conversion = 10; - break; - case 9: - conversion = 1; - break; - default: - return absl::InvalidArgumentError(exceeded_limit_message); - } - *nanos = i_nanos * conversion; - } - - return Status(); -} - -// If successful, stores the offset in seconds in "value" and returns true. -// Caller must ensure the first character of "offset" is "+" or "-". -bool ParseTimezoneOffset(absl::string_view offset, int* value) { - GOOGLE_DCHECK(offset[0] == '+' || offset[0] == '-'); - // Format of the offset: +DD:DD or -DD:DD. E.g., +08:00. - if (offset.length() != 6 || offset[3] != ':') { - return false; - } - int hours = 0, minutes = 0; - if (!safe_strto32(offset.substr(1, 2), &hours) || - !safe_strto32(offset.substr(4, 2), &minutes) || hours < 0 || - hours >= 24 || minutes < 0 || minutes >= 60) { - return false; - } - *value = (hours * 60 + minutes) * 60; - if (offset[0] == '-') { - *value = -*value; - } - return true; -} -} // namespace - -ProtoStreamObjectWriter::AnyWriter::AnyWriter(ProtoStreamObjectWriter* parent) - : parent_(parent), - ow_(), - invalid_(false), - data_(), - output_(&data_), - depth_(0), - is_well_known_type_(false), - well_known_type_render_(nullptr) {} - -ProtoStreamObjectWriter::AnyWriter::~AnyWriter() {} - -void ProtoStreamObjectWriter::AnyWriter::StartObject(absl::string_view name) { - ++depth_; - // If an object writer is absent, that means we have not called StartAny() - // before reaching here, which happens when we have data before the "@type" - // field. - if (ow_ == nullptr) { - // Save data before the "@type" field for later replay. - uninterpreted_events_.push_back(Event(Event::START_OBJECT, name)); - } else if (is_well_known_type_ && depth_ == 1) { - // For well-known types, the only other field besides "@type" should be a - // "value" field. - if (name != "value" && !invalid_) { - parent_->InvalidValue("Any", - "Expect a \"value\" field for well-known types."); - invalid_ = true; - } - ow_->StartObject(""); - } else { - // Forward the call to the child writer if: - // 1. the type is not a well-known type. - // 2. or, we are in a nested Any, Struct, or Value object. - ow_->StartObject(name); - } -} - -bool ProtoStreamObjectWriter::AnyWriter::EndObject() { - --depth_; - if (ow_ == nullptr) { - if (depth_ >= 0) { - // Save data before the "@type" field for later replay. - uninterpreted_events_.push_back(Event(Event::END_OBJECT)); - } - } else if (depth_ >= 0 || !is_well_known_type_) { - // As long as depth_ >= 0, we know we haven't reached the end of Any. - // Propagate these EndObject() calls to the contained ow_. For regular - // message types, we propagate the end of Any as well. - ow_->EndObject(); - } - // A negative depth_ implies that we have reached the end of Any - // object. Now we write out its contents. - if (depth_ < 0) { - WriteAny(); - return false; - } - return true; -} - -void ProtoStreamObjectWriter::AnyWriter::StartList(absl::string_view name) { - ++depth_; - if (ow_ == nullptr) { - // Save data before the "@type" field for later replay. - uninterpreted_events_.push_back(Event(Event::START_LIST, name)); - } else if (is_well_known_type_ && depth_ == 1) { - if (name != "value" && !invalid_) { - parent_->InvalidValue("Any", - "Expect a \"value\" field for well-known types."); - invalid_ = true; - } - ow_->StartList(""); - } else { - ow_->StartList(name); - } -} - -void ProtoStreamObjectWriter::AnyWriter::EndList() { - --depth_; - if (depth_ < 0) { - GOOGLE_LOG(DFATAL) << "Mismatched EndList found, should not be possible"; - depth_ = 0; - } - if (ow_ == nullptr) { - // Save data before the "@type" field for later replay. - uninterpreted_events_.push_back(Event(Event::END_LIST)); - } else { - ow_->EndList(); - } -} - -void ProtoStreamObjectWriter::AnyWriter::RenderDataPiece( - absl::string_view name, const DataPiece& value) { - // Start an Any only at depth_ 0. Other RenderDataPiece calls with "@type" - // should go to the contained ow_ as they indicate nested Anys. - if (depth_ == 0 && ow_ == nullptr && name == "@type") { - StartAny(value); - } else if (ow_ == nullptr) { - // Save data before the "@type" field. - uninterpreted_events_.push_back(Event(name, value)); - } else if (depth_ == 0 && is_well_known_type_) { - if (name != "value" && !invalid_) { - parent_->InvalidValue("Any", - "Expect a \"value\" field for well-known types."); - invalid_ = true; - } - if (well_known_type_render_ == nullptr) { - // Only Any and Struct don't have a special type render but both of - // them expect a JSON object (i.e., a StartObject() call). - if (value.type() != DataPiece::TYPE_NULL && !invalid_) { - parent_->InvalidValue("Any", "Expect a JSON object."); - invalid_ = true; - } - } else { - ow_->ProtoWriter::StartObject(""); - Status status = (*well_known_type_render_)(ow_.get(), value); - if (!status.ok()) ow_->InvalidValue("Any", status.message()); - ow_->ProtoWriter::EndObject(); - } - } else { - ow_->RenderDataPiece(name, value); - } -} - -void ProtoStreamObjectWriter::AnyWriter::StartAny(const DataPiece& value) { - // Figure out the type url. This is a copy-paste from WriteString but we also - // need the value, so we can't just call through to that. - if (value.type() == DataPiece::TYPE_STRING) { - type_url_ = std::string(value.str()); - } else { - absl::StatusOr s = value.ToString(); - if (!s.ok()) { - parent_->InvalidValue("String", s.status().message()); - invalid_ = true; - return; - } - type_url_ = s.value(); - } - // Resolve the type url, and report an error if we failed to resolve it. - absl::StatusOr resolved_type = - parent_->typeinfo()->ResolveTypeUrl(type_url_); - if (!resolved_type.ok()) { - parent_->InvalidValue("Any", resolved_type.status().message()); - invalid_ = true; - return; - } - // At this point, type is never null. - const google::protobuf::Type* type = resolved_type.value(); - - well_known_type_render_ = FindTypeRenderer(type_url_); - if (well_known_type_render_ != nullptr || - // Explicitly list Any and Struct here because they don't have a - // custom renderer. - type->name() == kAnyType || type->name() == kStructType) { - is_well_known_type_ = true; - } - - // Create our object writer and initialize it with the first StartObject - // call. - ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo(), *type, &output_, - parent_->listener(), - parent_->options_)); - - // Don't call StartObject() for well-known types yet. Depending on the - // type of actual data, we may not need to call StartObject(). For - // example: - // { - // "@type": "type.googleapis.com/google.protobuf.Value", - // "value": [1, 2, 3], - // } - // With the above JSON representation, we will only call StartList() on the - // contained ow_. - if (!is_well_known_type_) { - ow_->StartObject(""); - } - - // Now we know the proto type and can interpret all data fields we gathered - // before the "@type" field. - for (int i = 0; i < uninterpreted_events_.size(); ++i) { - uninterpreted_events_[i].Replay(this); - } -} - -void ProtoStreamObjectWriter::AnyWriter::WriteAny() { - if (ow_ == nullptr) { - if (uninterpreted_events_.empty()) { - // We never got any content, so just return immediately, which is - // equivalent to writing an empty Any. - return; - } else { - // There are uninterpreted data, but we never got a "@type" field. - if (!invalid_) { - parent_->InvalidValue("Any", - absl::StrCat("Missing @type for any field in ", - parent_->master_type_.name())); - invalid_ = true; - } - return; - } - } - // Render the type_url and value fields directly to the stream. - // type_url has tag 1 and value has tag 2. - WireFormatLite::WriteString(1, type_url_, parent_->stream()); - if (!data_.empty()) { - WireFormatLite::WriteBytes(2, data_, parent_->stream()); - } -} - -void ProtoStreamObjectWriter::AnyWriter::Event::Replay( - AnyWriter* writer) const { - switch (type_) { - case START_OBJECT: - writer->StartObject(name_); - break; - case END_OBJECT: - writer->EndObject(); - break; - case START_LIST: - writer->StartList(name_); - break; - case END_LIST: - writer->EndList(); - break; - case RENDER_DATA_PIECE: - writer->RenderDataPiece(name_, value_); - break; - } -} - -void ProtoStreamObjectWriter::AnyWriter::Event::DeepCopy() { - // DataPiece only contains a string reference. To make sure the referenced - // string value stays valid, we make a copy of the string value and update - // DataPiece to reference our own copy. - if (value_.type() == DataPiece::TYPE_STRING) { - absl::StrAppend(&value_storage_, value_.str()); - value_ = DataPiece(value_storage_, value_.use_strict_base64_decoding()); - } else if (value_.type() == DataPiece::TYPE_BYTES) { - value_storage_ = value_.ToBytes().value(); - value_ = - DataPiece(value_storage_, true, value_.use_strict_base64_decoding()); - } -} - -ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter* enclosing, - ItemType item_type, bool is_placeholder, - bool is_list) - : BaseElement(nullptr), - ow_(enclosing), - any_(), - item_type_(item_type), - is_placeholder_(is_placeholder), - is_list_(is_list) { - if (item_type_ == ANY) { - any_.reset(new AnyWriter(ow_)); - } -} - -ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter::Item* parent, - ItemType item_type, bool is_placeholder, - bool is_list) - : BaseElement(parent), - ow_(this->parent()->ow_), - any_(), - item_type_(item_type), - is_placeholder_(is_placeholder), - is_list_(is_list) { - if (item_type == ANY) { - any_.reset(new AnyWriter(ow_)); - } -} - -bool ProtoStreamObjectWriter::Item::InsertMapKeyIfNotPresent( - absl::string_view map_key) { - return map_keys_.insert(std::string(map_key)).second; -} - - -ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject( - absl::string_view name) { - if (invalid_depth() > 0) { - IncrementInvalidDepth(); - return this; - } - - // Starting the root message. Create the root Item and return. - // ANY message type does not need special handling, just set the ItemType - // to ANY. - if (current_ == nullptr) { - ProtoWriter::StartObject(name); - current_.reset(new Item( - this, master_type_.name() == kAnyType ? Item::ANY : Item::MESSAGE, - false, false)); - - // If master type is a special type that needs extra values to be written to - // stream, we write those values. - if (master_type_.name() == kStructType) { - // Struct has a map field called "fields". - // https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/struct.proto - // "fields": [ - Push("fields", Item::MAP, true, true); - return this; - } - - if (master_type_.name() == kStructValueType) { - // We got a StartObject call with google.protobuf.Value field. The only - // object within that type is a struct type. So start a struct. - // - // The struct field in Value type is named "struct_value" - // https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/struct.proto - // Also start the map field "fields" within the struct. - // "struct_value": { - // "fields": [ - Push("struct_value", Item::MESSAGE, true, false); - Push("fields", Item::MAP, true, true); - return this; - } - - if (master_type_.name() == kStructListValueType) { - InvalidValue(kStructListValueType, - "Cannot start root message with ListValue."); - } - - return this; - } - - // Send all ANY events to AnyWriter. - if (current_->IsAny()) { - current_->any()->StartObject(name); - return this; - } - - // If we are within a map, we render name as keys and send StartObject to the - // value field. - if (current_->IsMap()) { - if (!ValidMapKey(name)) { - IncrementInvalidDepth(); - return this; - } - - // Map is a repeated field of message type with a "key" and a "value" field. - // https://developers.google.com/protocol-buffers/docs/proto3?hl=en#maps - // message MapFieldEntry { - // key_type key = 1; - // value_type value = 2; - // } - // - // repeated MapFieldEntry map_field = N; - // - // That means, we render the following element within a list (hence no - // name): - // { "key": "", "value": { - Push("", Item::MESSAGE, false, false); - ProtoWriter::RenderDataPiece("key", - DataPiece(name, use_strict_base64_decoding())); - Push("value", IsAny(*Lookup("value")) ? Item::ANY : Item::MESSAGE, true, - false); - - // Make sure we are valid so far after starting map fields. - if (invalid_depth() > 0) return this; - - // If top of stack is g.p.Struct type, start the struct the map field within - // it. - if (element() != nullptr && IsStruct(*element()->parent_field())) { - // Render "fields": [ - Push("fields", Item::MAP, true, true); - return this; - } - - // If top of stack is g.p.Value type, start the Struct within it. - if (element() != nullptr && IsStructValue(*element()->parent_field())) { - // Render - // "struct_value": { - // "fields": [ - Push("struct_value", Item::MESSAGE, true, false); - Push("fields", Item::MAP, true, true); - } - return this; - } - - const google::protobuf::Field* field = BeginNamed(name, false); - - if (field == nullptr) return this; - - // Legacy JSON map is a list of key value pairs. Starts a map entry object. - if (options_.use_legacy_json_map_format && name.empty()) { - Push(name, IsAny(*field) ? Item::ANY : Item::MESSAGE, false, false); - return this; - } - - if (IsMap(*field)) { - // Begin a map. A map is triggered by a StartObject() call if the current - // field has a map type. - // A map type is always repeated, hence set is_list to true. - // Render - // "": [ - Push(name, Item::MAP, false, true); - return this; - } - - if (options_.disable_implicit_message_list) { - // If the incoming object is repeated, the top-level object on stack should - // be list. Report an error otherwise. - if (IsRepeated(*field) && !current_->is_list()) { - IncrementInvalidDepth(); - - if (!options_.suppress_implicit_message_list_error) { - InvalidValue( - field->name(), - "Starting an object in a repeated field but the parent object " - "is not a list"); - } - return this; - } - } - - if (IsStruct(*field)) { - // Start a struct object. - // Render - // "": { - // "fields": { - Push(name, Item::MESSAGE, false, false); - Push("fields", Item::MAP, true, true); - return this; - } - - if (IsStructValue(*field)) { - // We got a StartObject call with google.protobuf.Value field. The only - // object within that type is a struct type. So start a struct. - // Render - // "": { - // "struct_value": { - // "fields": { - Push(name, Item::MESSAGE, false, false); - Push("struct_value", Item::MESSAGE, true, false); - Push("fields", Item::MAP, true, true); - return this; - } - - if (field->kind() != google::protobuf::Field::TYPE_GROUP && - field->kind() != google::protobuf::Field::TYPE_MESSAGE) { - IncrementInvalidDepth(); - if (!options_.suppress_object_to_scalar_error) { - InvalidValue(field->name(), "Starting an object on a scalar field"); - } - - return this; - } - - // A regular message type. Pass it directly to ProtoWriter. - // Render - // "": { - Push(name, IsAny(*field) ? Item::ANY : Item::MESSAGE, false, false); - return this; -} - -ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndObject() { - if (invalid_depth() > 0) { - DecrementInvalidDepth(); - return this; - } - - if (current_ == nullptr) return this; - - if (current_->IsAny()) { - if (current_->any()->EndObject()) return this; - } - - Pop(); - - return this; -} - - -ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList( - absl::string_view name) { - if (invalid_depth() > 0) { - IncrementInvalidDepth(); - return this; - } - - // Since we cannot have a top-level repeated item in protobuf, the only way - // this is valid is if we start a special type google.protobuf.ListValue or - // google.protobuf.Value. - if (current_ == nullptr) { - if (!name.empty()) { - InvalidName(name, "Root element should not be named."); - IncrementInvalidDepth(); - return this; - } - - // If master type is a special type that needs extra values to be written to - // stream, we write those values. - if (master_type_.name() == kStructValueType) { - // We got a StartList with google.protobuf.Value master type. This means - // we have to start the "list_value" within google.protobuf.Value. - // - // See - // https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/struct.proto - // - // Render - // "": { - // "list_value": { - // "values": [ // Start this list. - ProtoWriter::StartObject(name); - current_.reset(new Item(this, Item::MESSAGE, false, false)); - Push("list_value", Item::MESSAGE, true, false); - Push("values", Item::MESSAGE, true, true); - return this; - } - - if (master_type_.name() == kStructListValueType) { - // We got a StartList with google.protobuf.ListValue master type. This - // means we have to start the "values" within google.protobuf.ListValue. - // - // Render - // "": { - // "values": [ // Start this list. - ProtoWriter::StartObject(name); - current_.reset(new Item(this, Item::MESSAGE, false, false)); - Push("values", Item::MESSAGE, true, true); - return this; - } - - // Send the event to ProtoWriter so proper errors can be reported. - // - // Render a regular list: - // "": [ - ProtoWriter::StartList(name); - current_.reset(new Item(this, Item::MESSAGE, false, true)); - return this; - } - - if (current_->IsAny()) { - current_->any()->StartList(name); - return this; - } - - // If the top of stack is a map, we are starting a list value within a map. - // Since map does not allow repeated values, this can only happen when the map - // value is of a special type that renders a list in JSON. These can be one - // of 3 cases: - // i. We are rendering a list value within google.protobuf.Struct - // ii. We are rendering a list value within google.protobuf.Value - // iii. We are rendering a list value with type google.protobuf.ListValue. - if (current_->IsMap()) { - if (!ValidMapKey(name)) { - IncrementInvalidDepth(); - return this; - } - - // Start the repeated map entry object. - // Render - // { "key": "", "value": { - Push("", Item::MESSAGE, false, false); - ProtoWriter::RenderDataPiece("key", - DataPiece(name, use_strict_base64_decoding())); - Push("value", Item::MESSAGE, true, false); - - // Make sure we are valid after pushing all above items. - if (invalid_depth() > 0) return this; - - // case i and ii above. Start "list_value" field within g.p.Value - if (element() != nullptr && element()->parent_field() != nullptr) { - // Render - // "list_value": { - // "values": [ // Start this list - if (IsStructValue(*element()->parent_field())) { - Push("list_value", Item::MESSAGE, true, false); - Push("values", Item::MESSAGE, true, true); - return this; - } - - // Render - // "values": [ - if (IsStructListValue(*element()->parent_field())) { - // case iii above. Bind directly to g.p.ListValue - Push("values", Item::MESSAGE, true, true); - return this; - } - } - - // Report an error. - InvalidValue("Map", absl::StrCat("Cannot have repeated items ('", name, - "') within a map.")); - return this; - } - - // When name is empty and stack is not empty, we are rendering an item within - // a list. - if (name.empty()) { - if (element() != nullptr && element()->parent_field() != nullptr) { - if (IsStructValue(*element()->parent_field())) { - // Since it is g.p.Value, we bind directly to the list_value. - // Render - // { // g.p.Value item within the list - // "list_value": { - // "values": [ - Push("", Item::MESSAGE, false, false); - Push("list_value", Item::MESSAGE, true, false); - Push("values", Item::MESSAGE, true, true); - return this; - } - - if (IsStructListValue(*element()->parent_field())) { - // Since it is g.p.ListValue, we bind to it directly. - // Render - // { // g.p.ListValue item within the list - // "values": [ - Push("", Item::MESSAGE, false, false); - Push("values", Item::MESSAGE, true, true); - return this; - } - } - - // Pass the event to underlying ProtoWriter. - Push(name, Item::MESSAGE, false, true); - return this; - } - - // name is not empty - const google::protobuf::Field* field = Lookup(name); - - if (field == nullptr) { - IncrementInvalidDepth(); - return this; - } - - if (IsStructValue(*field)) { - // If g.p.Value is repeated, start that list. Otherwise, start the - // "list_value" within it. - if (IsRepeated(*field)) { - // Render it just like a regular repeated field. - // "": [ - Push(name, Item::MESSAGE, false, true); - return this; - } - - // Start the "list_value" field. - // Render - // "": { - // "list_value": { - // "values": [ - Push(name, Item::MESSAGE, false, false); - Push("list_value", Item::MESSAGE, true, false); - Push("values", Item::MESSAGE, true, true); - return this; - } - - if (IsStructListValue(*field)) { - // If g.p.ListValue is repeated, start that list. Otherwise, start the - // "values" within it. - if (IsRepeated(*field)) { - // Render it just like a regular repeated field. - // "": [ - Push(name, Item::MESSAGE, false, true); - return this; - } - - // Start the "values" field within g.p.ListValue. - // Render - // "": { - // "values": [ - Push(name, Item::MESSAGE, false, false); - Push("values", Item::MESSAGE, true, true); - return this; - } - - // If we are here, the field should be repeated. Report an error otherwise. - if (!IsRepeated(*field)) { - IncrementInvalidDepth(); - InvalidName(name, "Proto field is not repeating, cannot start list."); - return this; - } - - if (IsMap(*field)) { - if (options_.use_legacy_json_map_format) { - Push(name, Item::MESSAGE, false, true); - return this; - } - InvalidValue("Map", absl::StrCat("Cannot bind a list to map for field '", - name, "'.")); - IncrementInvalidDepth(); - return this; - } - - // Pass the event to ProtoWriter. - // Render - // "": [ - Push(name, Item::MESSAGE, false, true); - return this; -} - -ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndList() { - if (invalid_depth() > 0) { - DecrementInvalidDepth(); - return this; - } - - if (current_ == nullptr) return this; - - if (current_->IsAny()) { - current_->any()->EndList(); - return this; - } - - Pop(); - return this; -} - -Status ProtoStreamObjectWriter::RenderStructValue(ProtoStreamObjectWriter* ow, - const DataPiece& data) { - std::string struct_field_name; - switch (data.type()) { - case DataPiece::TYPE_INT32: { - if (ow->options_.struct_integers_as_strings) { - absl::StatusOr int_value = data.ToInt32(); - if (int_value.ok()) { - ow->ProtoWriter::RenderDataPiece( - "string_value", - DataPiece(SimpleDtoa(int_value.value()), true)); - return Status(); - } - } - struct_field_name = "number_value"; - break; - } - case DataPiece::TYPE_UINT32: { - if (ow->options_.struct_integers_as_strings) { - absl::StatusOr int_value = data.ToUint32(); - if (int_value.ok()) { - ow->ProtoWriter::RenderDataPiece( - "string_value", - DataPiece(SimpleDtoa(int_value.value()), true)); - return Status(); - } - } - struct_field_name = "number_value"; - break; - } - case DataPiece::TYPE_INT64: { - // If the option to treat integers as strings is set, then render them as - // strings. Otherwise, fallback to rendering them as double. - if (ow->options_.struct_integers_as_strings) { - absl::StatusOr int_value = data.ToInt64(); - if (int_value.ok()) { - ow->ProtoWriter::RenderDataPiece( - "string_value", DataPiece(absl::StrCat(int_value.value()), true)); - return Status(); - } - } - struct_field_name = "number_value"; - break; - } - case DataPiece::TYPE_UINT64: { - // If the option to treat integers as strings is set, then render them as - // strings. Otherwise, fallback to rendering them as double. - if (ow->options_.struct_integers_as_strings) { - absl::StatusOr int_value = data.ToUint64(); - if (int_value.ok()) { - ow->ProtoWriter::RenderDataPiece( - "string_value", DataPiece(absl::StrCat(int_value.value()), true)); - return Status(); - } - } - struct_field_name = "number_value"; - break; - } - case DataPiece::TYPE_FLOAT: { - if (ow->options_.struct_integers_as_strings) { - absl::StatusOr float_value = data.ToFloat(); - if (float_value.ok()) { - ow->ProtoWriter::RenderDataPiece( - "string_value", - DataPiece(SimpleDtoa(float_value.value()), true)); - return Status(); - } - } - struct_field_name = "number_value"; - break; - } - case DataPiece::TYPE_DOUBLE: { - if (ow->options_.struct_integers_as_strings) { - absl::StatusOr double_value = data.ToDouble(); - if (double_value.ok()) { - ow->ProtoWriter::RenderDataPiece( - "string_value", - DataPiece(SimpleDtoa(double_value.value()), true)); - return Status(); - } - } - struct_field_name = "number_value"; - break; - } - case DataPiece::TYPE_STRING: { - struct_field_name = "string_value"; - break; - } - case DataPiece::TYPE_BOOL: { - struct_field_name = "bool_value"; - break; - } - case DataPiece::TYPE_NULL: { - struct_field_name = "null_value"; - break; - } - default: { - return absl::InvalidArgumentError( - "Invalid struct data type. Only number, string, boolean or null " - "values are supported."); - } - } - ow->ProtoWriter::RenderDataPiece(struct_field_name, data); - return Status(); -} - -Status ProtoStreamObjectWriter::RenderTimestamp(ProtoStreamObjectWriter* ow, - const DataPiece& data) { - if (data.type() == DataPiece::TYPE_NULL) return Status(); - if (data.type() != DataPiece::TYPE_STRING) { - return absl::InvalidArgumentError( - absl::StrCat("Invalid data type for timestamp, value is ", - data.ValueAsStringOrDefault(""))); - } - - absl::string_view value(data.str()); - - int timezone_offset_seconds = 0; - if (absl::EndsWith(value, "Z")) { - value = value.substr(0, value.size() - 1); - } else { - size_t pos = value.find_last_of("+-"); - if (pos == std::string::npos || - !ParseTimezoneOffset(value.substr(pos), &timezone_offset_seconds)) { - return Status(absl::StatusCode::kInvalidArgument, - "Illegal timestamp format; timestamps must end with 'Z' " - "or have a valid timezone offset."); - } - value = value.substr(0, pos); - } - - absl::string_view s_secs, s_nanos; - SplitSecondsAndNanos(value, &s_secs, &s_nanos); - absl::Time tm; - std::string err; - if (!absl::ParseTime(kRfc3339TimeFormatNoPadding, s_secs, &tm, &err)) { - return Status(absl::StatusCode::kInvalidArgument, - absl::StrCat("Invalid time format: ", err)); - } - - int32_t nanos = 0; - Status nanos_status = GetNanosFromStringPiece( - s_nanos, "Invalid time format, failed to parse nano seconds", - "Timestamp value exceeds limits", &nanos); - if (!nanos_status.ok()) { - return nanos_status; - } - - int64_t seconds = absl::ToUnixSeconds(tm) - timezone_offset_seconds; - if (seconds > kTimestampMaxSeconds || seconds < kTimestampMinSeconds) { - return Status(absl::StatusCode::kInvalidArgument, - "Timestamp value exceeds limits"); - } - - ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds)); - ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos)); - return Status(); -} - -static inline absl::Status RenderOneFieldPath(ProtoStreamObjectWriter* ow, - absl::string_view path) { - ow->ProtoWriter::RenderDataPiece( - "paths", DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase), true)); - return Status(); -} - -Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow, - const DataPiece& data) { - if (data.type() == DataPiece::TYPE_NULL) return Status(); - if (data.type() != DataPiece::TYPE_STRING) { - return absl::InvalidArgumentError( - absl::StrCat("Invalid data type for field mask, value is ", - data.ValueAsStringOrDefault(""))); - } - - // TODO(tsun): figure out how to do proto descriptor based snake case - // conversions as much as possible. Because ToSnakeCase sometimes returns the - // wrong value. - return DecodeCompactFieldMaskPaths(data.str(), - std::bind(&RenderOneFieldPath, ow, _1)); -} - -Status ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow, - const DataPiece& data) { - if (data.type() == DataPiece::TYPE_NULL) return Status(); - if (data.type() != DataPiece::TYPE_STRING) { - return absl::InvalidArgumentError( - absl::StrCat("Invalid data type for duration, value is ", - data.ValueAsStringOrDefault(""))); - } - - absl::string_view value(data.str()); - - if (!absl::EndsWith(value, "s")) { - return absl::InvalidArgumentError( - "Illegal duration format; duration must end with 's'"); - } - value = value.substr(0, value.size() - 1); - int sign = 1; - if (absl::StartsWith(value, "-")) { - sign = -1; - value = value.substr(1); - } - - absl::string_view s_secs, s_nanos; - SplitSecondsAndNanos(value, &s_secs, &s_nanos); - uint64_t unsigned_seconds; - if (!safe_strtou64(s_secs, &unsigned_seconds)) { - return absl::InvalidArgumentError( - "Invalid duration format, failed to parse seconds"); - } - - int32_t nanos = 0; - Status nanos_status = GetNanosFromStringPiece( - s_nanos, "Invalid duration format, failed to parse nano seconds", - "Duration value exceeds limits", &nanos); - if (!nanos_status.ok()) { - return nanos_status; - } - nanos = sign * nanos; - - int64_t seconds = sign * unsigned_seconds; - if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds || - nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) { - return absl::InvalidArgumentError("Duration value exceeds limits"); - } - - ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds)); - ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos)); - return Status(); -} - -Status ProtoStreamObjectWriter::RenderWrapperType(ProtoStreamObjectWriter* ow, - const DataPiece& data) { - if (data.type() == DataPiece::TYPE_NULL) return Status(); - ow->ProtoWriter::RenderDataPiece("value", data); - return Status(); -} - -ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece( - absl::string_view name, const DataPiece& data) { - Status status; - if (invalid_depth() > 0) return this; - - if (current_ == nullptr) { - const TypeRenderer* type_renderer = - FindTypeRenderer(GetFullTypeWithUrl(master_type_.name())); - if (type_renderer == nullptr) { - InvalidName(name, "Root element must be a message."); - return this; - } - // Render the special type. - // "": { - // ... Render special type ... - // } - ProtoWriter::StartObject(name); - status = (*type_renderer)(this, data); - if (!status.ok()) { - InvalidValue(master_type_.name(), - absl::StrCat("Field '", name, "', ", status.message())); - } - ProtoWriter::EndObject(); - return this; - } - - if (current_->IsAny()) { - current_->any()->RenderDataPiece(name, data); - return this; - } - - const google::protobuf::Field* field = nullptr; - if (current_->IsMap()) { - if (!ValidMapKey(name)) return this; - - field = Lookup("value"); - if (field == nullptr) { - GOOGLE_LOG(DFATAL) << "Map does not have a value field."; - return this; - } - - if (options_.ignore_null_value_map_entry) { - // If we are rendering explicit null values and the backend proto field is - // not of the google.protobuf.NullType type, interpret null as absence. - if (data.type() == DataPiece::TYPE_NULL && - field->type_url() != kStructNullValueTypeUrl) { - return this; - } - } - - // Render an item in repeated map list. - // { "key": "", "value": - Push("", Item::MESSAGE, false, false); - ProtoWriter::RenderDataPiece("key", - DataPiece(name, use_strict_base64_decoding())); - - const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url()); - if (type_renderer != nullptr) { - // Map's value type is a special type. Render it like a message: - // "value": { - // ... Render special type ... - // } - Push("value", Item::MESSAGE, true, false); - status = (*type_renderer)(this, data); - if (!status.ok()) { - InvalidValue(field->type_url(), - absl::StrCat("Field '", name, "', ", status.message())); - } - Pop(); - return this; - } - - // If we are rendering explicit null values and the backend proto field is - // not of the google.protobuf.NullType type, we do nothing. - if (data.type() == DataPiece::TYPE_NULL && - field->type_url() != kStructNullValueTypeUrl) { - Pop(); - return this; - } - - // Render the map value as a primitive type. - ProtoWriter::RenderDataPiece("value", data); - Pop(); - return this; - } - - field = Lookup(name); - if (field == nullptr) return this; - - // Check if the field is of special type. Render it accordingly if so. - const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url()); - if (type_renderer != nullptr) { - // Pass through null value only for google.protobuf.Value. For other - // types we ignore null value just like for regular field types. - if (data.type() != DataPiece::TYPE_NULL || - field->type_url() == kStructValueTypeUrl) { - Push(name, Item::MESSAGE, false, false); - status = (*type_renderer)(this, data); - if (!status.ok()) { - InvalidValue(field->type_url(), - absl::StrCat("Field '", name, "', ", status.message())); - } - Pop(); - } - return this; - } - - // If we are rendering explicit null values and the backend proto field is - // not of the google.protobuf.NullType type, we do nothing. - if (data.type() == DataPiece::TYPE_NULL && - field->type_url() != kStructNullValueTypeUrl) { - return this; - } - - if (IsRepeated(*field) && !current_->is_list()) { - if (options_.disable_implicit_scalar_list) { - if (!options_.suppress_implicit_scalar_list_error) { - InvalidValue( - field->name(), - "Starting an primitive in a repeated field but the parent field " - "is not a list"); - } - - return this; - } - } - - ProtoWriter::RenderDataPiece(name, data); - return this; -} - -// Map of functions that are responsible for rendering well known type -// represented by the key. -std::unordered_map* - ProtoStreamObjectWriter::renderers_ = nullptr; -absl::once_flag writer_renderers_init_; - -void ProtoStreamObjectWriter::InitRendererMap() { - renderers_ = new std::unordered_map(); - (*renderers_)["type.googleapis.com/google.protobuf.Timestamp"] = - &ProtoStreamObjectWriter::RenderTimestamp; - (*renderers_)["type.googleapis.com/google.protobuf.Duration"] = - &ProtoStreamObjectWriter::RenderDuration; - (*renderers_)["type.googleapis.com/google.protobuf.FieldMask"] = - &ProtoStreamObjectWriter::RenderFieldMask; - (*renderers_)["type.googleapis.com/google.protobuf.Double"] = - &ProtoStreamObjectWriter::RenderWrapperType; - (*renderers_)["type.googleapis.com/google.protobuf.Float"] = - &ProtoStreamObjectWriter::RenderWrapperType; - (*renderers_)["type.googleapis.com/google.protobuf.Int64"] = - &ProtoStreamObjectWriter::RenderWrapperType; - (*renderers_)["type.googleapis.com/google.protobuf.UInt64"] = - &ProtoStreamObjectWriter::RenderWrapperType; - (*renderers_)["type.googleapis.com/google.protobuf.Int32"] = - &ProtoStreamObjectWriter::RenderWrapperType; - (*renderers_)["type.googleapis.com/google.protobuf.UInt32"] = - &ProtoStreamObjectWriter::RenderWrapperType; - (*renderers_)["type.googleapis.com/google.protobuf.Bool"] = - &ProtoStreamObjectWriter::RenderWrapperType; - (*renderers_)["type.googleapis.com/google.protobuf.String"] = - &ProtoStreamObjectWriter::RenderWrapperType; - (*renderers_)["type.googleapis.com/google.protobuf.Bytes"] = - &ProtoStreamObjectWriter::RenderWrapperType; - (*renderers_)["type.googleapis.com/google.protobuf.DoubleValue"] = - &ProtoStreamObjectWriter::RenderWrapperType; - (*renderers_)["type.googleapis.com/google.protobuf.FloatValue"] = - &ProtoStreamObjectWriter::RenderWrapperType; - (*renderers_)["type.googleapis.com/google.protobuf.Int64Value"] = - &ProtoStreamObjectWriter::RenderWrapperType; - (*renderers_)["type.googleapis.com/google.protobuf.UInt64Value"] = - &ProtoStreamObjectWriter::RenderWrapperType; - (*renderers_)["type.googleapis.com/google.protobuf.Int32Value"] = - &ProtoStreamObjectWriter::RenderWrapperType; - (*renderers_)["type.googleapis.com/google.protobuf.UInt32Value"] = - &ProtoStreamObjectWriter::RenderWrapperType; - (*renderers_)["type.googleapis.com/google.protobuf.BoolValue"] = - &ProtoStreamObjectWriter::RenderWrapperType; - (*renderers_)["type.googleapis.com/google.protobuf.StringValue"] = - &ProtoStreamObjectWriter::RenderWrapperType; - (*renderers_)["type.googleapis.com/google.protobuf.BytesValue"] = - &ProtoStreamObjectWriter::RenderWrapperType; - (*renderers_)["type.googleapis.com/google.protobuf.Value"] = - &ProtoStreamObjectWriter::RenderStructValue; - ::google::protobuf::internal::OnShutdown(&DeleteRendererMap); -} - -void ProtoStreamObjectWriter::DeleteRendererMap() { - delete ProtoStreamObjectWriter::renderers_; - renderers_ = nullptr; -} - -ProtoStreamObjectWriter::TypeRenderer* -ProtoStreamObjectWriter::FindTypeRenderer(const std::string& type_url) { - absl::call_once(writer_renderers_init_, InitRendererMap); - auto it = renderers_->find(type_url); - if (it == renderers_->end()) return nullptr; - return &it->second; -} - -bool ProtoStreamObjectWriter::ValidMapKey(absl::string_view unnormalized_name) { - if (current_ == nullptr) return true; - - if (!current_->InsertMapKeyIfNotPresent(unnormalized_name)) { - listener()->InvalidName( - location(), unnormalized_name, - absl::StrCat("Repeated map key: '", unnormalized_name, - "' is already set.")); - return false; - } - - return true; -} - -void ProtoStreamObjectWriter::Push( - absl::string_view name, Item::ItemType item_type, bool is_placeholder, - bool is_list) { - is_list ? ProtoWriter::StartList(name) : ProtoWriter::StartObject(name); - - // invalid_depth == 0 means it is a successful StartObject or StartList. - if (invalid_depth() == 0) - current_.reset( - new Item(current_.release(), item_type, is_placeholder, is_list)); -} - -void ProtoStreamObjectWriter::Pop() { - // Pop all placeholder items sending StartObject or StartList events to - // ProtoWriter according to is_list value. - while (current_ != nullptr && current_->is_placeholder()) { - PopOneElement(); - } - if (current_ != nullptr) { - PopOneElement(); - } -} - -void ProtoStreamObjectWriter::PopOneElement() { - current_->is_list() ? ProtoWriter::EndList() : ProtoWriter::EndObject(); - current_.reset(current_->pop()); -} - -bool ProtoStreamObjectWriter::IsMap(const google::protobuf::Field& field) { - if (field.type_url().empty() || - field.kind() != google::protobuf::Field::TYPE_MESSAGE || - field.cardinality() != google::protobuf::Field::CARDINALITY_REPEATED) { - return false; - } - const google::protobuf::Type* field_type = - typeinfo()->GetTypeByTypeUrl(field.type_url()); - - return converter::IsMap(field, *field_type); -} - -bool ProtoStreamObjectWriter::IsAny(const google::protobuf::Field& field) { - return GetTypeWithoutUrl(field.type_url()) == kAnyType; -} - -bool ProtoStreamObjectWriter::IsStruct(const google::protobuf::Field& field) { - return GetTypeWithoutUrl(field.type_url()) == kStructType; -} - -bool ProtoStreamObjectWriter::IsStructValue( - const google::protobuf::Field& field) { - return GetTypeWithoutUrl(field.type_url()) == kStructValueType; -} - -bool ProtoStreamObjectWriter::IsStructListValue( - const google::protobuf::Field& field) { - return GetTypeWithoutUrl(field.type_url()) == kStructListValueType; -} - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h deleted file mode 100644 index 35933c1477..0000000000 --- a/src/google/protobuf/util/internal/protostream_objectwriter.h +++ /dev/null @@ -1,457 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTWRITER_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTWRITER_H__ - -#include -#include -#include -#include - -#include "google/protobuf/type.pb.h" -#include "google/protobuf/io/coded_stream.h" -#include "google/protobuf/io/zero_copy_stream_impl.h" -#include "google/protobuf/descriptor.h" -#include "absl/container/flat_hash_set.h" -#include "absl/status/status.h" -#include "google/protobuf/stubs/bytestream.h" -#include "absl/strings/string_view.h" -#include "google/protobuf/port.h" -#include "google/protobuf/util/internal/datapiece.h" -#include "google/protobuf/util/internal/error_listener.h" -#include "google/protobuf/util/internal/proto_writer.h" -#include "google/protobuf/util/internal/structured_objectwriter.h" -#include "google/protobuf/util/internal/type_info.h" -#include "google/protobuf/util/type_resolver.h" - - -// Must be included last. -#include "google/protobuf/port_def.inc" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -class ObjectLocationTracker; - -// An ObjectWriter that can write protobuf bytes directly from writer events. -// This class supports all special types like Struct and Map. It uses -// the ProtoWriter class to write raw proto bytes. -// -// It also supports streaming. -class PROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter { - public: - // Options that control ProtoStreamObjectWriter class's behavior. - struct Options { - // Treats numeric inputs in google.protobuf.Struct as strings. Normally, - // numeric values are returned in double field "number_value" of - // google.protobuf.Struct. However, this can cause precision loss for - // int64/uint64/double inputs. This option is provided for cases that want - // to preserve number precision. - // - // TODO(skarvaje): Rename to struct_numbers_as_strings as it covers double - // as well. - bool struct_integers_as_strings; - - // Not treat unknown fields as an error. If there is an unknown fields, - // just ignore it and continue to process the rest. Note that this doesn't - // apply to unknown enum values. - bool ignore_unknown_fields; - - // Ignore unknown enum values. - bool ignore_unknown_enum_values; - - // If true, check if enum name in camel case or without underscore matches - // the field name. - bool use_lower_camel_for_enums; - - // If true, check if enum name in UPPER_CASE matches the field name. - bool case_insensitive_enum_parsing; - - // If true, skips rendering the map entry if map value is null unless the - // value type is google.protobuf.NullType. - bool ignore_null_value_map_entry; - - // If true, accepts repeated key/value pair for a map proto field. - bool use_legacy_json_map_format; - - // If true, disable implicitly creating message list. - bool disable_implicit_message_list; - - // If true, suppress the error of implicitly creating message list when it - // is disabled. - bool suppress_implicit_message_list_error; - - // If true, disable implicitly creating scalar list. - bool disable_implicit_scalar_list; - - // If true, suppress the error of implicitly creating scalar list when it - // is disabled. - bool suppress_implicit_scalar_list_error; - - // If true, suppress the error of rendering scalar field if the source is an - // object. - bool suppress_object_to_scalar_error; - - // If true, use the json name in missing fields errors. - bool use_json_name_in_missing_fields; - - Options() - : struct_integers_as_strings(false), - ignore_unknown_fields(false), - ignore_unknown_enum_values(false), - use_lower_camel_for_enums(false), - case_insensitive_enum_parsing(false), - ignore_null_value_map_entry(false), - use_legacy_json_map_format(false), - disable_implicit_message_list(false), - suppress_implicit_message_list_error(false), - disable_implicit_scalar_list(false), - suppress_implicit_scalar_list_error(false), - suppress_object_to_scalar_error(false), - use_json_name_in_missing_fields(false) {} - - // Default instance of Options with all options set to defaults. - static const Options& Defaults() { - static Options defaults; - return defaults; - } - }; - - // Constructor. Does not take ownership of any parameter passed in. - ProtoStreamObjectWriter(TypeResolver* type_resolver, - const google::protobuf::Type& type, - strings::ByteSink* output, ErrorListener* listener, - const ProtoStreamObjectWriter::Options& options = - ProtoStreamObjectWriter::Options::Defaults()); - ProtoStreamObjectWriter() = delete; - ProtoStreamObjectWriter(const ProtoStreamObjectWriter&) = delete; - ProtoStreamObjectWriter& operator=(const ProtoStreamObjectWriter&) = delete; - ~ProtoStreamObjectWriter() override; - - // ObjectWriter methods. - ProtoStreamObjectWriter* StartObject(absl::string_view name) override; - ProtoStreamObjectWriter* EndObject() override; - ProtoStreamObjectWriter* StartList(absl::string_view name) override; - ProtoStreamObjectWriter* EndList() override; - - // Renders a DataPiece 'value' into a field whose wire type is determined - // from the given field 'name'. - ProtoStreamObjectWriter* RenderDataPiece(absl::string_view name, - const DataPiece& data) override; - - protected: - // Function that renders a well known type with modified behavior. - typedef absl::Status (*TypeRenderer)(ProtoStreamObjectWriter*, - const DataPiece&); - - // Handles writing Anys out using nested object writers and the like. - class PROTOBUF_EXPORT AnyWriter { - public: - explicit AnyWriter(ProtoStreamObjectWriter* parent); - ~AnyWriter(); - - // Passes a StartObject call through to the Any writer. - void StartObject(absl::string_view name); - - // Passes an EndObject call through to the Any. Returns true if the any - // handled the EndObject call, false if the Any is now all done and is no - // longer needed. - bool EndObject(); - - // Passes a StartList call through to the Any writer. - void StartList(absl::string_view name); - - // Passes an EndList call through to the Any writer. - void EndList(); - - // Renders a data piece on the any. - void RenderDataPiece(absl::string_view name, const DataPiece& value); - - private: - // Before the "@type" field is encountered, we store all incoming data - // into this Event struct and replay them after we get the "@type" field. - class PROTOBUF_EXPORT Event { - public: - enum Type { - START_OBJECT = 0, - END_OBJECT = 1, - START_LIST = 2, - END_LIST = 3, - RENDER_DATA_PIECE = 4, - }; - - // Constructor for END_OBJECT and END_LIST events. - explicit Event(Type type) : type_(type), value_(DataPiece::NullData()) {} - - // Constructor for START_OBJECT and START_LIST events. - explicit Event(Type type, absl::string_view name) - : type_(type), name_(name), value_(DataPiece::NullData()) {} - - // Constructor for RENDER_DATA_PIECE events. - explicit Event(absl::string_view name, const DataPiece& value) - : type_(RENDER_DATA_PIECE), name_(name), value_(value) { - DeepCopy(); - } - - Event(const Event& other) - : type_(other.type_), name_(other.name_), value_(other.value_) { - DeepCopy(); - } - - Event& operator=(const Event& other) { - type_ = other.type_; - name_ = other.name_; - value_ = other.value_; - DeepCopy(); - return *this; - } - - void Replay(AnyWriter* writer) const; - - private: - void DeepCopy(); - - Type type_; - std::string name_; - DataPiece value_; - std::string value_storage_; - }; - - // Handles starting up the any once we have a type. - void StartAny(const DataPiece& value); - - // Writes the Any out to the parent writer in its serialized form. - void WriteAny(); - - // The parent of this writer, needed for various bits such as type info and - // the listeners. - ProtoStreamObjectWriter* parent_; - - // The nested object writer, used to write events. - std::unique_ptr ow_; - - // The type_url_ that this Any represents. - std::string type_url_; - - // Whether this any is invalid. This allows us to only report an invalid - // Any message a single time rather than every time we get a nested field. - bool invalid_; - - // The output data and wrapping ByteSink. - std::string data_; - strings::StringByteSink output_; - - // The depth within the Any, so we can track when we're done. - int depth_; - - // True if the type is a well-known type. Well-known types in Any - // has a special formatting: - // { - // "@type": "type.googleapis.com/google.protobuf.XXX", - // "value": , - // } - bool is_well_known_type_; - TypeRenderer* well_known_type_render_; - - // Store data before the "@type" field. - std::vector uninterpreted_events_; - }; - - // Represents an item in a stack of items used to keep state between - // ObjectWrier events. - class PROTOBUF_EXPORT Item : public BaseElement { - public: - // Indicates the type of item. - enum ItemType { - MESSAGE, // Simple message - MAP, // Proto3 map type - ANY, // Proto3 Any type - }; - - // Constructor for the root item. - Item(ProtoStreamObjectWriter* enclosing, ItemType item_type, - bool is_placeholder, bool is_list); - - // Constructor for a field of a message. - Item(Item* parent, ItemType item_type, bool is_placeholder, bool is_list); - Item() = delete; - Item(const Item&) = delete; - Item& operator=(const Item&) = delete; - - ~Item() override {} - - // These functions return true if the element type is corresponding to the - // type in function name. - bool IsMap() { return item_type_ == MAP; } - bool IsAny() { return item_type_ == ANY; } - - AnyWriter* any() const { return any_.get(); } - - Item* parent() const override { - return static_cast(BaseElement::parent()); - } - - // Inserts map key into hash set if and only if the key did NOT already - // exist in hash set. - // The hash set (map_keys_) is ONLY used to keep track of map keys. - // Return true if insert successfully; returns false if the map key was - // already present. - bool InsertMapKeyIfNotPresent(absl::string_view map_key); - - bool is_placeholder() const { return is_placeholder_; } - bool is_list() const { return is_list_; } - - private: - // Used for access to variables of the enclosing instance of - // ProtoStreamObjectWriter. - ProtoStreamObjectWriter* ow_; - - // A writer for Any objects, handles all Any-related nonsense. - std::unique_ptr any_; - - // The type of this element, see enum for permissible types. - ItemType item_type_; - - // Set of map keys already seen for the type_. Used to validate incoming - // messages so no map key appears more than once. - absl::flat_hash_set map_keys_; - - // Conveys whether this Item is a placeholder or not. Placeholder items are - // pushed to stack to account for special types. - bool is_placeholder_; - - // Conveys whether this Item is a list or not. This is used to send - // StartList or EndList calls to underlying ObjectWriter. - bool is_list_; - }; - - ProtoStreamObjectWriter(const TypeInfo* typeinfo, - const google::protobuf::Type& type, - strings::ByteSink* output, ErrorListener* listener); - - ProtoStreamObjectWriter(const TypeInfo* typeinfo, - const google::protobuf::Type& type, - strings::ByteSink* output, ErrorListener* listener, - const ProtoStreamObjectWriter::Options& options); - - // Returns true if the field is a map. - inline bool IsMap(const google::protobuf::Field& field); - - // Returns true if the field is an any. - inline bool IsAny(const google::protobuf::Field& field); - - // Returns true if the field is google.protobuf.Struct. - inline bool IsStruct(const google::protobuf::Field& field); - - // Returns true if the field is google.protobuf.Value. - inline bool IsStructValue(const google::protobuf::Field& field); - - // Returns true if the field is google.protobuf.ListValue. - inline bool IsStructListValue(const google::protobuf::Field& field); - - // Renders google.protobuf.Value in struct.proto. It picks the right oneof - // type based on value's type. - static absl::Status RenderStructValue(ProtoStreamObjectWriter* ow, - const DataPiece& data); - - // Renders google.protobuf.Timestamp value. - static absl::Status RenderTimestamp(ProtoStreamObjectWriter* ow, - const DataPiece& data); - - // Renders google.protobuf.FieldMask value. - static absl::Status RenderFieldMask(ProtoStreamObjectWriter* ow, - const DataPiece& data); - - // Renders google.protobuf.Duration value. - static absl::Status RenderDuration(ProtoStreamObjectWriter* ow, - const DataPiece& data); - - // Renders wrapper message types for primitive types in - // google/protobuf/wrappers.proto. - static absl::Status RenderWrapperType(ProtoStreamObjectWriter* ow, - const DataPiece& data); - - static void InitRendererMap(); - static void DeleteRendererMap(); - static TypeRenderer* FindTypeRenderer(const std::string& type_url); - - // Returns true if the map key for type_ is not duplicated key. - // If map key is duplicated key, this function returns false. - // Note that caller should make sure that the current proto element (current_) - // is of element type MAP or STRUCT_MAP. - // It also calls the appropriate error callback and unnormalzied_name is used - // for error string. - bool ValidMapKey(absl::string_view unnormalized_name); - - // Pushes an item on to the stack. Also calls either StartObject or StartList - // on the underlying ObjectWriter depending on whether is_list is false or - // not. - // is_placeholder conveys whether the item is a placeholder item or not. - // Placeholder items are pushed when adding auxiliary types' StartObject or - // StartList calls. - void Push(absl::string_view name, Item::ItemType item_type, - bool is_placeholder, bool is_list); - - - // Pops items from the stack. All placeholder items are popped until a - // non-placeholder item is found. - void Pop(); - - // Pops one element from the stack. Calls EndObject() or EndList() on the - // underlying ObjectWriter depending on the value of is_list_. - void PopOneElement(); - - private: - // Helper functions to create the map and find functions responsible for - // rendering well known types, keyed by type URL. - static std::unordered_map* renderers_; - - // Variables for describing the structure of the input tree: - // master_type_: descriptor for the whole protobuf message. - const google::protobuf::Type& master_type_; - - // The current element, variable for internal state processing. - std::unique_ptr current_; - - // Reference to the options that control this class's behavior. - const ProtoStreamObjectWriter::Options options_; -}; - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google - -#include "google/protobuf/port_undef.inc" - -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTWRITER_H__ diff --git a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc deleted file mode 100644 index 22a2bf0d70..0000000000 --- a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc +++ /dev/null @@ -1,3045 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google/protobuf/util/internal/protostream_objectwriter.h" - -#include // For size_t - -#include "google/protobuf/field_mask.pb.h" -#include "google/protobuf/timestamp.pb.h" -#include "google/protobuf/type.pb.h" -#include "google/protobuf/wrappers.pb.h" -#include "google/protobuf/io/zero_copy_stream_impl_lite.h" -#include "google/protobuf/descriptor.pb.h" -#include "google/protobuf/message.h" -#include "google/protobuf/util/internal/mock_error_listener.h" -#include -#include "google/protobuf/stubs/bytestream.h" -#include "absl/strings/string_view.h" -#include "google/protobuf/descriptor.h" -#include "google/protobuf/dynamic_message.h" -#include "google/protobuf/util/internal/constants.h" -#include "google/protobuf/util/internal/testdata/anys.pb.h" -#include "google/protobuf/util/internal/testdata/books.pb.h" -#include "google/protobuf/util/internal/testdata/field_mask.pb.h" -#include "google/protobuf/util/internal/testdata/maps.pb.h" -#include "google/protobuf/util/internal/testdata/oneofs.pb.h" -#include "google/protobuf/util/internal/testdata/proto3.pb.h" -#include "google/protobuf/util/internal/testdata/struct.pb.h" -#include "google/protobuf/util/internal/testdata/timestamp_duration.pb.h" -#include "google/protobuf/util/internal/testdata/wrappers.pb.h" -#include "google/protobuf/util/internal/type_info_test_helper.h" -#include "google/protobuf/util/message_differencer.h" -#include "google/protobuf/util/type_resolver_util.h" - - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - - -using proto_util_converter::testing::AnyM; -using proto_util_converter::testing::AnyOut; -using proto_util_converter::testing::Author; -using proto_util_converter::testing::Book; -using proto_util_converter::testing::FieldMaskTest; -using proto_util_converter::testing::Int32Wrapper; -using proto_util_converter::testing::MapIn; -using proto_util_converter::testing::Primitive; -using proto_util_converter::testing::Proto3Message; -using proto_util_converter::testing::Publisher; -using proto_util_converter::testing::StructType; -using proto_util_converter::testing::TestJsonName1; -using proto_util_converter::testing::TestJsonName2; -using proto_util_converter::testing::TimestampDuration; -using proto_util_converter::testing::ValueWrapper; -using proto_util_converter::testing::oneofs::OneOfsRequest; -using strings::GrowingArrayByteSink; -using ::testing::_; -using ::testing::Args; - - -namespace { -std::string GetTypeUrl(const Descriptor* descriptor) { - return std::string(kTypeServiceBaseUrl) + "/" + descriptor->full_name(); -} -} // namespace - -class BaseProtoStreamObjectWriterTest - : public ::testing::TestWithParam { - protected: - BaseProtoStreamObjectWriterTest() - : helper_(GetParam()), - listener_(), - output_(new GrowingArrayByteSink(1000)), - ow_() {} - - explicit BaseProtoStreamObjectWriterTest(const Descriptor* descriptor) - : helper_(GetParam()), - listener_(), - output_(new GrowingArrayByteSink(1000)), - ow_() { - std::vector descriptors; - descriptors.push_back(descriptor); - ResetTypeInfo(descriptors); - } - - explicit BaseProtoStreamObjectWriterTest( - std::vector descriptors) - : helper_(GetParam()), - listener_(), - output_(new GrowingArrayByteSink(1000)), - ow_() { - ResetTypeInfo(descriptors); - } - - void ResetTypeInfo(std::vector descriptors) { - GOOGLE_CHECK(!descriptors.empty()) << "Must have at least one descriptor!"; - helper_.ResetTypeInfo(descriptors); - ow_.reset(helper_.NewProtoWriter(GetTypeUrl(descriptors[0]), output_.get(), - &listener_, options_)); - } - - void ResetTypeInfo(const Descriptor* descriptor) { - std::vector descriptors; - descriptors.push_back(descriptor); - ResetTypeInfo(descriptors); - } - - ~BaseProtoStreamObjectWriterTest() override {} - - void CheckOutput(const Message& expected, int expected_length) { - size_t nbytes; - std::unique_ptr buffer(output_->GetBuffer(&nbytes)); - if (expected_length >= 0) { - EXPECT_EQ(expected_length, nbytes); - } - std::string str(buffer.get(), nbytes); - - std::stringbuf str_buf(str, std::ios_base::in); - std::istream istream(&str_buf); - std::unique_ptr message(expected.New()); - message->ParsePartialFromIstream(&istream); - - if (!MessageDifferencer::Equivalent(expected, *message)) { - EXPECT_EQ(expected.DebugString(), message->DebugString()); - } - } - - void CheckOutput(const Message& expected) { CheckOutput(expected, -1); } - - testing::TypeInfoTestHelper helper_; - MockErrorListener listener_; - std::unique_ptr output_; - std::unique_ptr ow_; - ProtoStreamObjectWriter::Options options_; -}; - -MATCHER_P(HasObjectLocation, expected, - "Verifies the expected object location") { - std::string actual = std::get<0>(arg).ToString(); - if (actual == expected) return true; - *result_listener << "actual location is: " << actual; - return false; -} - -class ProtoStreamObjectWriterTest : public BaseProtoStreamObjectWriterTest { - protected: - ProtoStreamObjectWriterTest() - : BaseProtoStreamObjectWriterTest(Book::descriptor()) {} - - void ResetProtoWriter() { ResetTypeInfo(Book::descriptor()); } - - ~ProtoStreamObjectWriterTest() override {} -}; - -INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest, - ProtoStreamObjectWriterTest, - ::testing::Values( - testing::USE_TYPE_RESOLVER)); - -TEST_P(ProtoStreamObjectWriterTest, EmptyObject) { - Book empty; - ow_->StartObject("")->EndObject(); - CheckOutput(empty, 0); -} - -TEST_P(ProtoStreamObjectWriterTest, SimpleObject) { - std::string content("My content"); - - Book book; - book.set_title("My Title"); - book.set_length(222); - book.set_content(content); - - ow_->StartObject("") - ->RenderString("title", "My Title") - ->RenderInt32("length", 222) - ->RenderBytes("content", content) - ->EndObject(); - CheckOutput(book); -} - -TEST_P(ProtoStreamObjectWriterTest, SimpleMessage) { - Book book; - book.set_title("Some Book"); - book.set_length(102); - Publisher* publisher = book.mutable_publisher(); - publisher->set_name("My Publisher"); - Author* robert = book.mutable_author(); - robert->set_alive(true); - robert->set_name("robert"); - robert->add_pseudonym("bob"); - robert->add_pseudonym("bobby"); - robert->add_friend_()->set_name("john"); - - ow_->StartObject("") - ->RenderString("title", "Some Book") - ->RenderInt32("length", 102) - ->StartObject("publisher") - ->RenderString("name", "My Publisher") - ->EndObject() - ->StartObject("author") - ->RenderBool("alive", true) - ->RenderString("name", "robert") - ->StartList("pseudonym") - ->RenderString("", "bob") - ->RenderString("", "bobby") - ->EndList() - ->StartList("friend") - ->StartObject("") - ->RenderString("name", "john") - ->EndObject() - ->EndList() - ->EndObject() - ->EndObject(); - CheckOutput(book); -} - -TEST_P(ProtoStreamObjectWriterTest, CustomJsonName) { - Book book; - Author* robert = book.mutable_author(); - robert->set_id(12345); - robert->set_name("robert"); - - ow_->StartObject("") - ->StartObject("author") - ->RenderUint64("@id", 12345) - ->RenderString("name", "robert") - ->EndObject() - ->EndObject(); - CheckOutput(book); -} - -// Test that two messages can have different fields mapped to the same JSON -// name. See: https://github.com/protocolbuffers/protobuf/issues/1415 -TEST_P(ProtoStreamObjectWriterTest, ConflictingJsonName) { - ResetTypeInfo(TestJsonName1::descriptor()); - TestJsonName1 message1; - message1.set_one_value(12345); - ow_->StartObject("")->RenderInt32("value", 12345)->EndObject(); - CheckOutput(message1); - - ResetTypeInfo(TestJsonName2::descriptor()); - TestJsonName2 message2; - message2.set_another_value(12345); - ow_->StartObject("")->RenderInt32("value", 12345)->EndObject(); - CheckOutput(message2); -} - - -TEST_P(ProtoStreamObjectWriterTest, IntEnumValuesAreAccepted) { - Book book; - book.set_title("Some Book"); - book.set_type(proto_util_converter::testing::Book::KIDS); - Author* robert = book.mutable_author(); - robert->set_name("robert"); - - ow_->StartObject("") - ->RenderString("title", "Some Book") - ->RenderString("type", "2") - ->StartObject("author") - ->RenderString("name", "robert") - ->EndObject() - ->EndObject(); - CheckOutput(book); -} - -TEST_P(ProtoStreamObjectWriterTest, EnumValuesWithDifferentCaseIsRejected) { - Book book; - book.set_title("Some Book"); - Author* robert = book.mutable_author(); - robert->set_name("robert"); - - options_.case_insensitive_enum_parsing = false; - ResetProtoWriter(); - - ow_->StartObject("") - ->RenderString("title", "Some Book") - ->RenderString("type", "action_and_adventure") - ->StartObject("author") - ->RenderString("name", "robert") - ->EndObject() - ->EndObject(); - CheckOutput(book); -} - -TEST_P(ProtoStreamObjectWriterTest, EnumValuesWithSameCaseIsAccepted) { - Book book; - book.set_title("Some Book"); - book.set_type(proto_util_converter::testing::Book::ACTION_AND_ADVENTURE); - Author* robert = book.mutable_author(); - robert->set_name("robert"); - - options_.case_insensitive_enum_parsing = false; - ResetProtoWriter(); - - ow_->StartObject("") - ->RenderString("title", "Some Book") - ->RenderString("type", "ACTION_AND_ADVENTURE") - ->StartObject("author") - ->RenderString("name", "robert") - ->EndObject() - ->EndObject(); - CheckOutput(book); -} - -TEST_P(ProtoStreamObjectWriterTest, EnumValuesWithDifferentCaseIsAccepted) { - Book book; - book.set_title("Some Book"); - book.set_type(proto_util_converter::testing::Book::ACTION_AND_ADVENTURE); - Author* robert = book.mutable_author(); - robert->set_name("robert"); - - options_.case_insensitive_enum_parsing = true; - ResetProtoWriter(); - - ow_->StartObject("") - ->RenderString("title", "Some Book") - ->RenderString("type", "action_AND_adventure") - ->StartObject("author") - ->RenderString("name", "robert") - ->EndObject() - ->EndObject(); - CheckOutput(book); -} - -TEST_P(ProtoStreamObjectWriterTest, EnumValuesWithoutUnderscoreAreAccepted) { - Book book; - book.set_title("Some Book"); - book.set_type(proto_util_converter::testing::Book::ACTION_AND_ADVENTURE); - Author* robert = book.mutable_author(); - robert->set_name("robert"); - - options_.use_lower_camel_for_enums = true; - ResetProtoWriter(); - - ow_->StartObject("") - ->RenderString("title", "Some Book") - ->RenderString("type", "ACTIONANDADVENTURE") - ->StartObject("author") - ->RenderString("name", "robert") - ->EndObject() - ->EndObject(); - CheckOutput(book); -} - -TEST_P(ProtoStreamObjectWriterTest, EnumValuesInCamelCaseAreAccepted) { - Book book; - book.set_title("Some Book"); - book.set_type(proto_util_converter::testing::Book::ACTION_AND_ADVENTURE); - Author* robert = book.mutable_author(); - robert->set_name("robert"); - - options_.use_lower_camel_for_enums = true; - ResetProtoWriter(); - - ow_->StartObject("") - ->RenderString("title", "Some Book") - ->RenderString("type", "actionAndAdventure") - ->StartObject("author") - ->RenderString("name", "robert") - ->EndObject() - ->EndObject(); - CheckOutput(book); -} - -TEST_P(ProtoStreamObjectWriterTest, - EnumValuesInCamelCaseRemoveDashAndUnderscoreAreAccepted) { - Book book; - book.set_title("Some Book"); - book.set_type(proto_util_converter::testing::Book::ACTION_AND_ADVENTURE); - Author* robert = book.mutable_author(); - robert->set_name("robert"); - - options_.use_lower_camel_for_enums = true; - options_.case_insensitive_enum_parsing = false; - ResetProtoWriter(); - - ow_->StartObject("") - ->RenderString("title", "Some Book") - ->RenderString("type", "action-And_Adventure") - ->StartObject("author") - ->RenderString("name", "robert") - ->EndObject() - ->EndObject(); - CheckOutput(book); -} - -TEST_P(ProtoStreamObjectWriterTest, - EnumValuesInCamelCaseWithNameNotUppercaseAreAccepted) { - Book book; - book.set_title("Some Book"); - book.set_type(proto_util_converter::testing::Book::arts_and_photography); - Author* robert = book.mutable_author(); - robert->set_name("robert"); - - options_.use_lower_camel_for_enums = true; - ResetProtoWriter(); - - ow_->StartObject("") - ->RenderString("title", "Some Book") - ->RenderString("type", "artsAndPhotography") - ->StartObject("author") - ->RenderString("name", "robert") - ->EndObject() - ->EndObject(); - CheckOutput(book); -} - -TEST_P(ProtoStreamObjectWriterTest, PrimitiveFromStringConversion) { - Primitive full; - full.set_fix32(101); - full.set_u32(102); - full.set_i32(-103); - full.set_sf32(-104); - full.set_s32(-105); - full.set_fix64(40000000001L); - full.set_u64(40000000002L); - full.set_i64(-40000000003L); - full.set_sf64(-40000000004L); - full.set_s64(-40000000005L); - full.set_str("string1"); - full.set_bytes("Some Bytes"); - full.set_float_(3.14f); - full.set_double_(-4.05L); - full.set_bool_(true); - full.add_rep_fix32(201); - full.add_rep_u32(202); - full.add_rep_i32(-203); - full.add_rep_sf32(-204); - full.add_rep_s32(-205); - full.add_rep_fix64(80000000001L); - full.add_rep_u64(80000000002L); - full.add_rep_i64(-80000000003L); - full.add_rep_sf64(-80000000004L); - full.add_rep_s64(-80000000005L); - full.add_rep_str("string2"); - full.add_rep_bytes("More Bytes"); - full.add_rep_float(6.14f); - full.add_rep_double(-8.05L); - full.add_rep_bool(false); - - ResetTypeInfo(Primitive::descriptor()); - - ow_->StartObject("") - ->RenderString("fix32", "101") - ->RenderString("u32", "102") - ->RenderString("i32", "-103") - ->RenderString("sf32", "-104") - ->RenderString("s32", "-105") - ->RenderString("fix64", "40000000001") - ->RenderString("u64", "40000000002") - ->RenderString("i64", "-40000000003") - ->RenderString("sf64", "-40000000004") - ->RenderString("s64", "-40000000005") - ->RenderString("str", "string1") - ->RenderString("bytes", "U29tZSBCeXRlcw==") // "Some Bytes" - ->RenderString("float", "3.14") - ->RenderString("double", "-4.05") - ->RenderString("bool", "true") - ->StartList("rep_fix32") - ->RenderString("", "201") - ->EndList() - ->StartList("rep_u32") - ->RenderString("", "202") - ->EndList() - ->StartList("rep_i32") - ->RenderString("", "-203") - ->EndList() - ->StartList("rep_sf32") - ->RenderString("", "-204") - ->EndList() - ->StartList("rep_s32") - ->RenderString("", "-205") - ->EndList() - ->StartList("rep_fix64") - ->RenderString("", "80000000001") - ->EndList() - ->StartList("rep_u64") - ->RenderString("", "80000000002") - ->EndList() - ->StartList("rep_i64") - ->RenderString("", "-80000000003") - ->EndList() - ->StartList("rep_sf64") - ->RenderString("", "-80000000004") - ->EndList() - ->StartList("rep_s64") - ->RenderString("", "-80000000005") - ->EndList() - ->StartList("rep_str") - ->RenderString("", "string2") - ->EndList() - ->StartList("rep_bytes") - ->RenderString("", "TW9yZSBCeXRlcw==") // "More Bytes" - ->EndList() - ->StartList("rep_float") - ->RenderString("", "6.14") - ->EndList() - ->StartList("rep_double") - ->RenderString("", "-8.05") - ->EndList() - ->StartList("rep_bool") - ->RenderString("", "false") - ->EndList() - ->EndObject(); - CheckOutput(full); -} - -TEST_P(ProtoStreamObjectWriterTest, InfinityInputTest) { - Primitive full; - full.set_double_(std::numeric_limits::infinity()); - full.set_float_(std::numeric_limits::infinity()); - full.set_str("-Infinity"); - - ResetTypeInfo(Primitive::descriptor()); - - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("TYPE_INT32"), - absl::string_view("\"Infinity\""))) - .With(Args<0>(HasObjectLocation("i32"))); - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("TYPE_UINT32"), - absl::string_view("\"Infinity\""))) - .With(Args<0>(HasObjectLocation("u32"))); - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("TYPE_SFIXED64"), - absl::string_view("\"-Infinity\""))) - .With(Args<0>(HasObjectLocation("sf64"))); - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("TYPE_BOOL"), - absl::string_view("\"Infinity\""))) - .With(Args<0>(HasObjectLocation("bool"))); - - ow_->StartObject("") - ->RenderString("double", "Infinity") - ->RenderString("float", "Infinity") - ->RenderString("i32", "Infinity") - ->RenderString("u32", "Infinity") - ->RenderString("sf64", "-Infinity") - ->RenderString("str", "-Infinity") - ->RenderString("bool", "Infinity") - ->EndObject(); - CheckOutput(full); -} - -TEST_P(ProtoStreamObjectWriterTest, NaNInputTest) { - Primitive full; - full.set_double_(std::numeric_limits::quiet_NaN()); - full.set_float_(std::numeric_limits::quiet_NaN()); - full.set_str("NaN"); - - ResetTypeInfo(Primitive::descriptor()); - - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("TYPE_INT32"), - absl::string_view("\"NaN\""))) - .With(Args<0>(HasObjectLocation("i32"))); - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("TYPE_UINT32"), - absl::string_view("\"NaN\""))) - .With(Args<0>(HasObjectLocation("u32"))); - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("TYPE_SFIXED64"), - absl::string_view("\"NaN\""))) - .With(Args<0>(HasObjectLocation("sf64"))); - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("TYPE_BOOL"), - absl::string_view("\"NaN\""))) - .With(Args<0>(HasObjectLocation("bool"))); - - ow_->StartObject("") - ->RenderString("double", "NaN") - ->RenderString("float", "NaN") - ->RenderString("i32", "NaN") - ->RenderString("u32", "NaN") - ->RenderString("sf64", "NaN") - ->RenderString("str", "NaN") - ->RenderString("bool", "NaN") - ->EndObject(); - - CheckOutput(full); -} - -TEST_P(ProtoStreamObjectWriterTest, ImplicitPrimitiveList) { - Book expected; - Author* author = expected.mutable_author(); - author->set_name("The Author"); - author->add_pseudonym("first"); - author->add_pseudonym("second"); - - ow_->StartObject("") - ->StartObject("author") - ->RenderString("name", "The Author") - ->RenderString("pseudonym", "first") - ->RenderString("pseudonym", "second") - ->EndObject() - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, - LastWriteWinsOnNonRepeatedPrimitiveFieldWithDuplicates) { - Book expected; - Author* author = expected.mutable_author(); - author->set_name("second"); - - ow_->StartObject("") - ->StartObject("author") - ->RenderString("name", "first") - ->RenderString("name", "second") - ->EndObject() - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, ExplicitPrimitiveList) { - Book expected; - Author* author = expected.mutable_author(); - author->set_name("The Author"); - author->add_pseudonym("first"); - author->add_pseudonym("second"); - - ow_->StartObject("") - ->StartObject("author") - ->RenderString("name", "The Author") - ->StartList("pseudonym") - ->RenderString("", "first") - ->RenderString("", "second") - ->EndList() - ->EndObject() - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, NonRepeatedExplicitPrimitiveList) { - Book expected; - expected.set_allocated_author(new Author()); - - EXPECT_CALL( - listener_, - InvalidName(_, absl::string_view("name"), - absl::string_view( - "Proto field is not repeating, cannot start list."))) - .With(Args<0>(HasObjectLocation("author"))); - ow_->StartObject("") - ->StartObject("author") - ->StartList("name") - ->RenderString("", "first") - ->RenderString("", "second") - ->EndList() - ->EndObject() - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, ImplicitMessageList) { - Book expected; - Author* outer = expected.mutable_author(); - outer->set_name("outer"); - outer->set_alive(true); - Author* first = outer->add_friend_(); - first->set_name("first"); - Author* second = outer->add_friend_(); - second->set_name("second"); - - ow_->StartObject("") - ->StartObject("author") - ->RenderString("name", "outer") - ->RenderBool("alive", true) - ->StartObject("friend") - ->RenderString("name", "first") - ->EndObject() - ->StartObject("friend") - ->RenderString("name", "second") - ->EndObject() - ->EndObject() - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, DisableImplicitMessageList) { - options_.disable_implicit_message_list = true; - options_.suppress_implicit_message_list_error = true; - ResetProtoWriter(); - - Book expected; - // The repeated friend field of the author is empty. - expected.mutable_author(); - - EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); - - ow_->StartObject("") - ->StartObject("author") - ->StartObject("friend") - ->RenderString("name", "first") - ->EndObject() - ->StartObject("friend") - ->RenderString("name", "second") - ->EndObject() - ->EndObject() - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, - DisableImplicitMessageListWithoutErrorSuppressed) { - options_.disable_implicit_message_list = true; - ResetProtoWriter(); - - Book expected; - // The repeated friend field of the author is empty. - expected.mutable_author(); - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("friend"), - absl::string_view( - "Starting an object in a repeated field but the parent object " - "is not a list"))) - .With(Args<0>(HasObjectLocation("author"))) - .Times(2); - - ow_->StartObject("") - ->StartObject("author") - ->StartObject("friend") - ->RenderString("name", "first") - ->EndObject() - ->StartObject("friend") - ->RenderString("name", "second") - ->EndObject() - ->EndObject() - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, - LastWriteWinsOnNonRepeatedMessageFieldWithDuplicates) { - Book expected; - Author* author = expected.mutable_author(); - author->set_name("The Author"); - Publisher* publisher = expected.mutable_publisher(); - publisher->set_name("second"); - - ow_->StartObject("") - ->StartObject("author") - ->RenderString("name", "The Author") - ->EndObject() - ->StartObject("publisher") - ->RenderString("name", "first") - ->EndObject() - ->StartObject("publisher") - ->RenderString("name", "second") - ->EndObject() - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, ExplicitMessageList) { - Book expected; - Author* outer = expected.mutable_author(); - outer->set_name("outer"); - outer->set_alive(true); - Author* first = outer->add_friend_(); - first->set_name("first"); - Author* second = outer->add_friend_(); - second->set_name("second"); - - ow_->StartObject("") - ->StartObject("author") - ->RenderString("name", "outer") - ->RenderBool("alive", true) - ->StartList("friend") - ->StartObject("") - ->RenderString("name", "first") - ->EndObject() - ->StartObject("") - ->RenderString("name", "second") - ->EndObject() - ->EndList() - ->EndObject() - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, NonRepeatedExplicitMessageList) { - Book expected; - Author* author = expected.mutable_author(); - author->set_name("The Author"); - - EXPECT_CALL( - listener_, - InvalidName(_, absl::string_view("publisher"), - absl::string_view( - "Proto field is not repeating, cannot start list."))) - .With(Args<0>(HasObjectLocation(""))); - ow_->StartObject("") - ->StartObject("author") - ->RenderString("name", "The Author") - ->EndObject() - ->StartList("publisher") - ->StartObject("") - ->RenderString("name", "first") - ->EndObject() - ->StartObject("") - ->RenderString("name", "second") - ->EndObject() - ->EndList() - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, UnknownFieldAtRoot) { - Book empty; - - EXPECT_CALL(listener_, InvalidName(_, absl::string_view("unknown"), - absl::string_view("Cannot find field."))) - .With(Args<0>(HasObjectLocation(""))); - ow_->StartObject("")->RenderString("unknown", "Nope!")->EndObject(); - CheckOutput(empty, 0); -} - -TEST_P(ProtoStreamObjectWriterTest, UnknownFieldAtAuthorFriend) { - Book expected; - Author* paul = expected.mutable_author(); - paul->set_name("Paul"); - Author* mark = paul->add_friend_(); - mark->set_name("Mark"); - Author* john = paul->add_friend_(); - john->set_name("John"); - Author* luke = paul->add_friend_(); - luke->set_name("Luke"); - - EXPECT_CALL(listener_, InvalidName(_, absl::string_view("address"), - absl::string_view("Cannot find field."))) - .With(Args<0>(HasObjectLocation("author.friend[1]"))); - ow_->StartObject("") - ->StartObject("author") - ->RenderString("name", "Paul") - ->StartList("friend") - ->StartObject("") - ->RenderString("name", "Mark") - ->EndObject() - ->StartObject("") - ->RenderString("name", "John") - ->RenderString("address", "Patmos") - ->EndObject() - ->StartObject("") - ->RenderString("name", "Luke") - ->EndObject() - ->EndList() - ->EndObject() - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, UnknownObjectAtRoot) { - Book empty; - - EXPECT_CALL(listener_, InvalidName(_, absl::string_view("unknown"), - absl::string_view("Cannot find field."))) - .With(Args<0>(HasObjectLocation(""))); - ow_->StartObject("")->StartObject("unknown")->EndObject()->EndObject(); - CheckOutput(empty, 0); -} - -TEST_P(ProtoStreamObjectWriterTest, UnknownObjectAtAuthor) { - Book expected; - Author* author = expected.mutable_author(); - author->set_name("William"); - author->add_pseudonym("Bill"); - - EXPECT_CALL(listener_, InvalidName(_, absl::string_view("wife"), - absl::string_view("Cannot find field."))) - .With(Args<0>(HasObjectLocation("author"))); - ow_->StartObject("") - ->StartObject("author") - ->RenderString("name", "William") - ->StartObject("wife") - ->RenderString("name", "Hilary") - ->EndObject() - ->RenderString("pseudonym", "Bill") - ->EndObject() - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, UnknownListAtRoot) { - Book empty; - - EXPECT_CALL(listener_, InvalidName(_, absl::string_view("unknown"), - absl::string_view("Cannot find field."))) - .With(Args<0>(HasObjectLocation(""))); - ow_->StartObject("")->StartList("unknown")->EndList()->EndObject(); - CheckOutput(empty, 0); -} - -TEST_P(ProtoStreamObjectWriterTest, UnknownListAtPublisher) { - Book expected; - expected.set_title("Brainwashing"); - Publisher* publisher = expected.mutable_publisher(); - publisher->set_name("propaganda"); - - EXPECT_CALL(listener_, InvalidName(_, absl::string_view("alliance"), - absl::string_view("Cannot find field."))) - .With(Args<0>(HasObjectLocation("publisher"))); - ow_->StartObject("") - ->StartObject("publisher") - ->RenderString("name", "propaganda") - ->StartList("alliance") - ->EndList() - ->EndObject() - ->RenderString("title", "Brainwashing") - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, IgnoreUnknownFieldAtRoot) { - Book empty; - - options_.ignore_unknown_fields = true; - ResetProtoWriter(); - - EXPECT_CALL(listener_, InvalidName(_, _, _)).Times(0); - ow_->StartObject("")->RenderString("unknown", "Nope!")->EndObject(); - CheckOutput(empty, 0); -} - -TEST_P(ProtoStreamObjectWriterTest, IgnoreUnknownFieldAtAuthorFriend) { - Book expected; - Author* paul = expected.mutable_author(); - paul->set_name("Paul"); - Author* mark = paul->add_friend_(); - mark->set_name("Mark"); - Author* john = paul->add_friend_(); - john->set_name("John"); - Author* luke = paul->add_friend_(); - luke->set_name("Luke"); - - options_.ignore_unknown_fields = true; - ResetProtoWriter(); - - EXPECT_CALL(listener_, InvalidName(_, _, _)).Times(0); - ow_->StartObject("") - ->StartObject("author") - ->RenderString("name", "Paul") - ->StartList("friend") - ->StartObject("") - ->RenderString("name", "Mark") - ->EndObject() - ->StartObject("") - ->RenderString("name", "John") - ->RenderString("address", "Patmos") - ->EndObject() - ->StartObject("") - ->RenderString("name", "Luke") - ->EndObject() - ->EndList() - ->EndObject() - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, IgnoreUnknownObjectAtRoot) { - Book empty; - - options_.ignore_unknown_fields = true; - ResetProtoWriter(); - - EXPECT_CALL(listener_, InvalidName(_, absl::string_view("unknown"), - absl::string_view("Cannot find field."))) - .Times(0); - ow_->StartObject("")->StartObject("unknown")->EndObject()->EndObject(); - CheckOutput(empty, 0); -} - -TEST_P(ProtoStreamObjectWriterTest, IgnoreUnknownObjectAtAuthor) { - Book expected; - Author* author = expected.mutable_author(); - author->set_name("William"); - author->add_pseudonym("Bill"); - - options_.ignore_unknown_fields = true; - ResetProtoWriter(); - - EXPECT_CALL(listener_, InvalidName(_, _, _)).Times(0); - ow_->StartObject("") - ->StartObject("author") - ->RenderString("name", "William") - ->StartObject("wife") - ->RenderString("name", "Hilary") - ->EndObject() - ->RenderString("pseudonym", "Bill") - ->EndObject() - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, IgnoreUnknownListAtRoot) { - Book empty; - - options_.ignore_unknown_fields = true; - ResetProtoWriter(); - - EXPECT_CALL(listener_, InvalidName(_, _, _)).Times(0); - ow_->StartObject("")->StartList("unknown")->EndList()->EndObject(); - CheckOutput(empty, 0); -} - -TEST_P(ProtoStreamObjectWriterTest, IgnoreUnknownListAtPublisher) { - Book expected; - expected.set_title("Brainwashing"); - Publisher* publisher = expected.mutable_publisher(); - publisher->set_name("propaganda"); - - options_.ignore_unknown_fields = true; - ResetProtoWriter(); - - EXPECT_CALL(listener_, InvalidName(_, _, _)).Times(0); - ow_->StartObject("") - ->StartObject("publisher") - ->RenderString("name", "propaganda") - ->StartList("alliance") - ->EndList() - ->EndObject() - ->RenderString("title", "Brainwashing") - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, - IgnoreUnknownFieldsDontIgnoreUnknownEnumValues) { - ResetTypeInfo(Proto3Message::descriptor()); - - Proto3Message expected; - EXPECT_CALL( - listener_, - InvalidValue(_, - absl::string_view( - "type.googleapis.com/" - "proto_util_converter.testing.Proto3Message.NestedEnum"), - absl::string_view("\"someunknownvalueyouwillneverknow\""))) - .With(Args<0>(HasObjectLocation("enum_value"))); - ow_->StartObject("") - ->RenderString("enumValue", "someunknownvalueyouwillneverknow") - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, AcceptUnknownEnumValue) { - ResetTypeInfo(Proto3Message::descriptor()); - - Proto3Message expected; - expected.set_enum_value(static_cast(12345)); - - EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); - ow_->StartObject("")->RenderInt32("enumValue", 12345)->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, MissingRequiredField) { - Book expected; - expected.set_title("My Title"); - expected.set_allocated_publisher(new Publisher()); - - EXPECT_CALL(listener_, MissingField(_, absl::string_view("name"))) - .With(Args<0>(HasObjectLocation("publisher"))); - ow_->StartObject("") - ->StartObject("publisher") - ->EndObject() - ->RenderString("title", "My Title") - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, InvalidFieldValueAtRoot) { - Book empty; - - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("TYPE_UINT32"), - absl::string_view("\"garbage\""))) - .With(Args<0>(HasObjectLocation("length"))); - ow_->StartObject("")->RenderString("length", "garbage")->EndObject(); - CheckOutput(empty, 0); -} - -TEST_P(ProtoStreamObjectWriterTest, MultipleInvalidFieldValues) { - Book expected; - expected.set_title("My Title"); - - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("TYPE_UINT32"), - absl::string_view("\"-400\""))) - .With(Args<0>(HasObjectLocation("length"))); - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("TYPE_INT64"), - absl::string_view("\"3.14\""))) - .With(Args<0>(HasObjectLocation("published"))); - ow_->StartObject("") - ->RenderString("length", "-400") - ->RenderString("published", "3.14") - ->RenderString("title", "My Title") - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, UnnamedFieldAtRoot) { - Book empty; - - EXPECT_CALL(listener_, - InvalidName(_, absl::string_view(""), - absl::string_view("Proto fields must have a name."))) - .With(Args<0>(HasObjectLocation(""))); - ow_->StartObject("")->RenderFloat("", 3.14)->EndObject(); - CheckOutput(empty, 0); -} - -TEST_P(ProtoStreamObjectWriterTest, UnnamedFieldAtAuthor) { - Book expected; - expected.set_title("noname"); - expected.set_allocated_author(new Author()); - - EXPECT_CALL(listener_, - InvalidName(_, absl::string_view(""), - absl::string_view("Proto fields must have a name."))) - .With(Args<0>(HasObjectLocation("author"))); - ow_->StartObject("") - ->StartObject("author") - ->RenderInt32("", 123) - ->EndObject() - ->RenderString("title", "noname") - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, UnnamedListAtRoot) { - Book expected; - expected.set_title("noname"); - - EXPECT_CALL(listener_, - InvalidName(_, absl::string_view(""), - absl::string_view("Proto fields must have a name."))) - .With(Args<0>(HasObjectLocation(""))); - ow_->StartObject("") - ->StartList("") - ->EndList() - ->RenderString("title", "noname") - ->EndObject(); - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterTest, RootNamedObject) { - Book expected; - expected.set_title("Annie"); - - EXPECT_CALL( - listener_, - InvalidName(_, absl::string_view("oops"), - absl::string_view("Root element should not be named."))) - .With(Args<0>(HasObjectLocation(""))); - ow_->StartObject("oops")->RenderString("title", "Annie")->EndObject(); - CheckOutput(expected, 7); -} - -TEST_P(ProtoStreamObjectWriterTest, RootNamedList) { - Book empty; - - EXPECT_CALL( - listener_, - InvalidName(_, absl::string_view("oops"), - absl::string_view("Root element should not be named."))) - .With(Args<0>(HasObjectLocation(""))); - ow_->StartList("oops")->RenderString("", "item")->EndList(); - CheckOutput(empty, 0); -} - -TEST_P(ProtoStreamObjectWriterTest, RootUnnamedField) { - Book empty; - - EXPECT_CALL(listener_, - InvalidName(_, absl::string_view(""), - absl::string_view("Root element must be a message."))) - .With(Args<0>(HasObjectLocation(""))); - ow_->RenderBool("", true); - CheckOutput(empty, 0); -} - -TEST_P(ProtoStreamObjectWriterTest, RootNamedField) { - Book empty; - - EXPECT_CALL(listener_, - InvalidName(_, absl::string_view("oops"), - absl::string_view("Root element must be a message."))) - .With(Args<0>(HasObjectLocation(""))); - ow_->RenderBool("oops", true); - CheckOutput(empty, 0); -} - -TEST_P(ProtoStreamObjectWriterTest, NullValue) { - Book empty; - - ow_->RenderNull(""); - CheckOutput(empty, 0); -} - -TEST_P(ProtoStreamObjectWriterTest, NullValueForMessageField) { - Book empty; - - ow_->RenderNull("author"); - CheckOutput(empty, 0); -} - -TEST_P(ProtoStreamObjectWriterTest, NullValueForPrimitiveField) { - Book empty; - - ow_->RenderNull("length"); - CheckOutput(empty, 0); -} - -class ProtoStreamObjectWriterTimestampDurationTest - : public BaseProtoStreamObjectWriterTest { - protected: - ProtoStreamObjectWriterTimestampDurationTest() { - std::vector descriptors; - descriptors.push_back(TimestampDuration::descriptor()); - descriptors.push_back(google::protobuf::Timestamp::descriptor()); - descriptors.push_back(google::protobuf::Duration::descriptor()); - ResetTypeInfo(descriptors); - } -}; - -INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest, - ProtoStreamObjectWriterTimestampDurationTest, - ::testing::Values( - testing::USE_TYPE_RESOLVER)); - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, ParseTimestamp) { - TimestampDuration timestamp; - google::protobuf::Timestamp* ts = timestamp.mutable_ts(); - ts->set_seconds(1448249855); - ts->set_nanos(33155000); - - ow_->StartObject("") - ->RenderString("ts", "2015-11-23T03:37:35.033155Z") - ->EndObject(); - CheckOutput(timestamp); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, - ParseTimestampYearNotZeroPadded) { - TimestampDuration timestamp; - google::protobuf::Timestamp* ts = timestamp.mutable_ts(); - ts->set_seconds(-61665654145); - ts->set_nanos(33155000); - - ow_->StartObject("") - ->RenderString("ts", "15-11-23T03:37:35.033155Z") - ->EndObject(); - CheckOutput(timestamp); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, - ParseTimestampYearZeroPadded) { - TimestampDuration timestamp; - google::protobuf::Timestamp* ts = timestamp.mutable_ts(); - ts->set_seconds(-61665654145); - ts->set_nanos(33155000); - - ow_->StartObject("") - ->RenderString("ts", "0015-11-23T03:37:35.033155Z") - ->EndObject(); - CheckOutput(timestamp); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, - ParseTimestampWithPositiveOffset) { - TimestampDuration timestamp; - google::protobuf::Timestamp* ts = timestamp.mutable_ts(); - ts->set_seconds(1448249855); - ts->set_nanos(33155000); - - ow_->StartObject("") - ->RenderString("ts", "2015-11-23T11:47:35.033155+08:10") - ->EndObject(); - CheckOutput(timestamp); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, - ParseTimestampWithNegativeOffset) { - TimestampDuration timestamp; - google::protobuf::Timestamp* ts = timestamp.mutable_ts(); - ts->set_seconds(1448249855); - ts->set_nanos(33155000); - - ow_->StartObject("") - ->RenderString("ts", "2015-11-22T19:47:35.033155-07:50") - ->EndObject(); - CheckOutput(timestamp); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, - TimestampWithInvalidOffset1) { - TimestampDuration timestamp; - - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Timestamp"), - absl::string_view( - "Field 'ts', Illegal timestamp format; timestamps " - "must end with 'Z' or have a valid timezone offset."))); - - ow_->StartObject("")->RenderString("ts", "2016-03-07T15:14:23+")->EndObject(); - CheckOutput(timestamp); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, - TimestampWithInvalidOffset2) { - TimestampDuration timestamp; - - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Timestamp"), - absl::string_view( - "Field 'ts', Illegal timestamp format; timestamps " - "must end with 'Z' or have a valid timezone offset."))); - - ow_->StartObject("") - ->RenderString("ts", "2016-03-07T15:14:23+08-10") - ->EndObject(); - CheckOutput(timestamp); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, - TimestampWithInvalidOffset3) { - TimestampDuration timestamp; - - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Timestamp"), - absl::string_view( - "Field 'ts', Illegal timestamp format; timestamps " - "must end with 'Z' or have a valid timezone offset."))); - - ow_->StartObject("") - ->RenderString("ts", "2016-03-07T15:14:23+24:10") - ->EndObject(); - CheckOutput(timestamp); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, - TimestampWithInvalidOffset4) { - TimestampDuration timestamp; - - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Timestamp"), - absl::string_view( - "Field 'ts', Illegal timestamp format; timestamps " - "must end with 'Z' or have a valid timezone offset."))); - - ow_->StartObject("") - ->RenderString("ts", "2016-03-07T15:14:23+04:60") - ->EndObject(); - CheckOutput(timestamp); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError1) { - TimestampDuration timestamp; - - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Timestamp"), - absl::string_view( - "Field 'ts', Illegal timestamp format; timestamps " - "must end with 'Z' or have a valid timezone offset."))); - - ow_->StartObject("")->RenderString("ts", "")->EndObject(); - CheckOutput(timestamp); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError2) { - TimestampDuration timestamp; - - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Timestamp"), - absl::string_view("Field 'ts', Invalid time format: Failed to " - "parse input"))); - - ow_->StartObject("")->RenderString("ts", "Z")->EndObject(); - CheckOutput(timestamp); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError3) { - TimestampDuration timestamp; - - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Timestamp"), - absl::string_view( - "Field 'ts', Invalid time format, failed to parse nano " - "seconds"))); - - ow_->StartObject("") - ->RenderString("ts", "1970-01-01T00:00:00.ABZ") - ->EndObject(); - CheckOutput(timestamp); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError4) { - TimestampDuration timestamp; - - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Timestamp"), - absl::string_view("Field 'ts', Timestamp value exceeds limits"))); - - ow_->StartObject("") - ->RenderString("ts", "-8031-10-18T00:00:00.000Z") - ->EndObject(); - CheckOutput(timestamp); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError5) { - TimestampDuration timestamp; - - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Timestamp"), - absl::string_view( - "Field 'ts', Invalid time format, failed to parse nano " - "seconds"))); - - ow_->StartObject("") - // Whitespace in the Timestamp nanos is not allowed. - ->RenderString("ts", "2015-11-23T03:37:35.033155 Z") - ->EndObject(); - CheckOutput(timestamp); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError6) { - TimestampDuration timestamp; - - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Timestamp"), - absl::string_view( - "Field 'ts', Invalid time format, failed to parse nano " - "seconds"))); - - ow_->StartObject("") - // Whitespace in the Timestamp nanos is not allowed. - ->RenderString("ts", "2015-11-23T03:37:35.033155 1234Z") - ->EndObject(); - CheckOutput(timestamp); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError7) { - TimestampDuration timestamp; - - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Timestamp"), - absl::string_view( - "Field 'ts', Invalid time format, failed to parse nano " - "seconds"))); - - ow_->StartObject("") - // Non-numeric characters in the Timestamp nanos is not allowed. - ->RenderString("ts", "2015-11-23T03:37:35.033abc155Z") - ->EndObject(); - CheckOutput(timestamp); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError8) { - TimestampDuration timestamp; - - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Timestamp"), - absl::string_view("Field 'ts', Timestamp value exceeds limits"))); - - ow_->StartObject("") - ->RenderString("ts", "0-12-31T23:59:59.000Z") - ->EndObject(); - CheckOutput(timestamp); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, ParseDuration) { - TimestampDuration duration; - google::protobuf::Duration* dur = duration.mutable_dur(); - dur->set_seconds(1448216930); - dur->set_nanos(132262000); - - ow_->StartObject("")->RenderString("dur", "1448216930.132262s")->EndObject(); - CheckOutput(duration); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError1) { - TimestampDuration duration; - - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Duration"), - absl::string_view( - "Field 'dur', Illegal duration format; duration must " - "end with 's'"))); - - ow_->StartObject("")->RenderString("dur", "")->EndObject(); - CheckOutput(duration); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError2) { - TimestampDuration duration; - - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Duration"), - absl::string_view( - "Field 'dur', Invalid duration format, failed to parse " - "seconds"))); - - ow_->StartObject("")->RenderString("dur", "s")->EndObject(); - CheckOutput(duration); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError3) { - TimestampDuration duration; - - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Duration"), - absl::string_view("Field 'dur', Invalid duration format, failed to " - "parse nano seconds"))); - - ow_->StartObject("")->RenderString("dur", "123.DEFs")->EndObject(); - CheckOutput(duration); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError4) { - TimestampDuration duration; - - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Duration"), - absl::string_view("Field 'dur', Duration value exceeds limits"))); - - ow_->StartObject("")->RenderString("dur", "315576000002s")->EndObject(); - CheckOutput(duration); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError5) { - TimestampDuration duration; - - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Duration"), - absl::string_view("Field 'dur', Duration value exceeds limits"))); - - ow_->StartObject("")->RenderString("dur", "0.1000000001s")->EndObject(); - CheckOutput(duration); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, - MismatchedTimestampTypeInput) { - TimestampDuration timestamp; - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Timestamp"), - absl::string_view( - "Field 'ts', Invalid data type for timestamp, value is 1"))) - .With(Args<0>(HasObjectLocation("ts"))); - ow_->StartObject("")->RenderInt32("ts", 1)->EndObject(); - CheckOutput(timestamp); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, - MismatchedDurationTypeInput) { - TimestampDuration duration; - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Duration"), - absl::string_view( - "Field 'dur', Invalid data type for duration, value is 1"))) - .With(Args<0>(HasObjectLocation("dur"))); - ow_->StartObject("")->RenderInt32("dur", 1)->EndObject(); - CheckOutput(duration); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, TimestampAcceptsNull) { - TimestampDuration timestamp; - EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); - ow_->StartObject("")->RenderNull("ts")->EndObject(); - CheckOutput(timestamp); -} - -TEST_P(ProtoStreamObjectWriterTimestampDurationTest, DurationAcceptsNull) { - TimestampDuration duration; - EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); - ow_->StartObject("")->RenderNull("dur")->EndObject(); - CheckOutput(duration); -} - -class ProtoStreamObjectWriterStructTest - : public BaseProtoStreamObjectWriterTest { - protected: - ProtoStreamObjectWriterStructTest() { ResetProtoWriter(); } - - // Resets ProtoWriter with current set of options and other state. - void ResetProtoWriter() { - std::vector descriptors; - descriptors.push_back(StructType::descriptor()); - descriptors.push_back(google::protobuf::Struct::descriptor()); - ResetTypeInfo(descriptors); - } -}; - -INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest, - ProtoStreamObjectWriterStructTest, - ::testing::Values( - testing::USE_TYPE_RESOLVER)); - -// TODO(skarvaje): Write tests for failure cases. -TEST_P(ProtoStreamObjectWriterStructTest, StructRenderSuccess) { - StructType struct_type; - google::protobuf::Struct* s = struct_type.mutable_object(); - s->mutable_fields()->operator[]("k1").set_number_value(123); - s->mutable_fields()->operator[]("k2").set_bool_value(true); - - ow_->StartObject("") - ->StartObject("object") - ->RenderDouble("k1", 123) - ->RenderBool("k2", true) - ->EndObject() - ->EndObject(); - CheckOutput(struct_type); -} - -TEST_P(ProtoStreamObjectWriterStructTest, StructNullInputSuccess) { - StructType struct_type; - EXPECT_CALL(listener_, - InvalidName(_, absl::string_view(""), - absl::string_view("Proto fields must have a name."))) - .With(Args<0>(HasObjectLocation(""))); - ow_->StartObject("")->RenderNull("")->EndObject(); - CheckOutput(struct_type); -} - -TEST_P(ProtoStreamObjectWriterStructTest, StructInvalidInputFailure) { - StructType struct_type; - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.Struct"), - absl::string_view("true"))) - .With(Args<0>(HasObjectLocation("object"))); - - ow_->StartObject("")->RenderBool("object", true)->EndObject(); - CheckOutput(struct_type); -} - -TEST_P(ProtoStreamObjectWriterStructTest, StructAcceptsNull) { - StructType struct_type; - EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); - - ow_->StartObject("")->RenderNull("object")->EndObject(); - CheckOutput(struct_type); -} - -TEST_P(ProtoStreamObjectWriterStructTest, StructValuePreservesNull) { - StructType struct_type; - (*struct_type.mutable_object()->mutable_fields())["key"].set_null_value( - google::protobuf::NULL_VALUE); - EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); - - ow_->StartObject("") - ->StartObject("object") - ->RenderNull("key") - ->EndObject() - ->EndObject(); - CheckOutput(struct_type); -} - -TEST_P(ProtoStreamObjectWriterStructTest, SimpleRepeatedStructMapKeyTest) { - EXPECT_CALL(listener_, - InvalidName(_, absl::string_view("gBike"), - absl::string_view( - "Repeated map key: 'gBike' is already set."))); - ow_->StartObject("") - ->StartObject("object") - ->RenderString("gBike", "v1") - ->RenderString("gBike", "v2") - ->EndObject() - ->EndObject(); -} - -TEST_P(ProtoStreamObjectWriterStructTest, RepeatedStructMapListKeyTest) { - EXPECT_CALL( - listener_, - InvalidName(_, absl::string_view("k1"), - absl::string_view("Repeated map key: 'k1' is already set."))); - ow_->StartObject("") - ->StartObject("object") - ->RenderString("k1", "v1") - ->StartList("k1") - ->RenderString("", "v2") - ->EndList() - ->EndObject() - ->EndObject(); -} - -TEST_P(ProtoStreamObjectWriterStructTest, RepeatedStructMapObjectKeyTest) { - EXPECT_CALL( - listener_, - InvalidName(_, absl::string_view("k1"), - absl::string_view("Repeated map key: 'k1' is already set."))); - ow_->StartObject("") - ->StartObject("object") - ->StartObject("k1") - ->RenderString("sub_k1", "v1") - ->EndObject() - ->StartObject("k1") - ->RenderString("sub_k2", "v2") - ->EndObject() - ->EndObject() - ->EndObject(); -} - -TEST_P(ProtoStreamObjectWriterStructTest, OptionStructIntAsStringsTest) { - StructType struct_type; - google::protobuf::Struct* s = struct_type.mutable_object(); - s->mutable_fields()->operator[]("k1").set_string_value("123"); - s->mutable_fields()->operator[]("k2").set_bool_value(true); - s->mutable_fields()->operator[]("k3").set_string_value("-222222222"); - s->mutable_fields()->operator[]("k4").set_string_value("33333333"); - - options_.struct_integers_as_strings = true; - ResetProtoWriter(); - - ow_->StartObject("") - ->StartObject("object") - ->RenderDouble("k1", 123) - ->RenderBool("k2", true) - ->RenderInt64("k3", -222222222) - ->RenderUint64("k4", 33333333) - ->EndObject() - ->EndObject(); - CheckOutput(struct_type); -} - -TEST_P(ProtoStreamObjectWriterStructTest, Struct32BitIntsAndFloatsTest) { - StructType struct_type; - google::protobuf::Struct* s = struct_type.mutable_object(); - s->mutable_fields()->operator[]("k1").set_number_value(1.5); - s->mutable_fields()->operator[]("k2").set_number_value(100); - s->mutable_fields()->operator[]("k3").set_number_value(100); - ResetProtoWriter(); - - ow_->StartObject("") - ->StartObject("object") - ->RenderFloat("k1", 1.5) - ->RenderInt32("k2", 100) - ->RenderUint32("k3", 100) - ->EndObject() - ->EndObject(); - CheckOutput(struct_type); -} - -TEST_P(ProtoStreamObjectWriterStructTest, - Struct32BitIntsAndFloatsAsStringsTest) { - StructType struct_type; - google::protobuf::Struct* s = struct_type.mutable_object(); - s->mutable_fields()->operator[]("k1").set_string_value("1.5"); - s->mutable_fields()->operator[]("k2").set_string_value("100"); - s->mutable_fields()->operator[]("k3").set_string_value("100"); - - options_.struct_integers_as_strings = true; - ResetProtoWriter(); - - ow_->StartObject("") - ->StartObject("object") - ->RenderFloat("k1", 1.5) - ->RenderInt32("k2", 100) - ->RenderUint32("k3", 100) - ->EndObject() - ->EndObject(); - CheckOutput(struct_type); -} - -TEST_P(ProtoStreamObjectWriterStructTest, ValuePreservesNull) { - ValueWrapper value; - value.mutable_value()->set_null_value(google::protobuf::NULL_VALUE); - - EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); - ow_->StartObject("")->RenderNull("value")->EndObject(); - CheckOutput(value); -} - -class ProtoStreamObjectWriterMapTest : public BaseProtoStreamObjectWriterTest { - protected: - ProtoStreamObjectWriterMapTest() { - std::vector descriptors; - descriptors.push_back(MapIn::descriptor()); - descriptors.push_back(google::protobuf::DoubleValue::descriptor()); - ResetTypeInfo(descriptors); - } -}; - -INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest, - ProtoStreamObjectWriterMapTest, - ::testing::Values( - testing::USE_TYPE_RESOLVER)); - -TEST_P(ProtoStreamObjectWriterMapTest, MapShouldNotAcceptList) { - MapIn mm; - EXPECT_CALL( - listener_, - InvalidValue(_, absl::string_view("Map"), - absl::string_view( - "Cannot bind a list to map for field 'map_input'."))); - ow_->StartObject("") - ->StartList("map_input") - ->RenderString("a", "b") - ->EndList() - ->EndObject(); - CheckOutput(mm); -} - -TEST_P(ProtoStreamObjectWriterMapTest, MapAcceptsNullValue) { - // Null should not be a valid map value. - // See http://go/proto3-json-spec#heading=h.r2ddatp7y4vi - // This test is added for backward compatibility. - MapIn mm; - (*mm.mutable_map_input())["a"] = "b"; - (*mm.mutable_map_input())["x"] = ""; - ow_->StartObject("") - ->StartObject("map_input") - ->RenderString("a", "b") - ->RenderNull("x") - ->EndObject() - ->EndObject(); - CheckOutput(mm); -} - -TEST_P(ProtoStreamObjectWriterMapTest, MapShouldIgnoreNullValueEntry) { - options_.ignore_null_value_map_entry = true; - ResetTypeInfo(MapIn::descriptor()); - MapIn mm; - (*mm.mutable_map_input())["a"] = "b"; - ow_->StartObject("") - ->StartObject("map_input") - ->RenderString("a", "b") - ->RenderNull("x") - ->EndObject() - ->EndObject(); - CheckOutput(mm); -} - -TEST_P(ProtoStreamObjectWriterMapTest, RepeatedMapKeyTest) { - EXPECT_CALL( - listener_, - InvalidName(_, absl::string_view("k1"), - absl::string_view("Repeated map key: 'k1' is already set."))); - ow_->StartObject("") - ->RenderString("other", "test") - ->StartObject("map_input") - ->RenderString("k1", "v1") - ->RenderString("k1", "v2") - ->EndObject() - ->EndObject(); -} - -TEST_P(ProtoStreamObjectWriterMapTest, AnyInMap) { - MapIn mm; - google::protobuf::DoubleValue d; - d.set_value(40.2); - (*mm.mutable_map_any())["foo"].PackFrom(d); - ow_->StartObject("") - ->StartObject("map_any") - ->StartObject("foo") - ->RenderString("@type", "type.googleapis.com/google.protobuf.DoubleValue") - ->RenderDouble("value", 40.2) - ->EndObject() - ->EndObject() - ->EndObject(); - CheckOutput(mm); -} - -class ProtoStreamObjectWriterAnyTest : public BaseProtoStreamObjectWriterTest { - protected: - ProtoStreamObjectWriterAnyTest() { - std::vector descriptors; - descriptors.push_back(AnyOut::descriptor()); - descriptors.push_back(Book::descriptor()); - descriptors.push_back(google::protobuf::Any::descriptor()); - descriptors.push_back(google::protobuf::DoubleValue::descriptor()); - descriptors.push_back(google::protobuf::FieldMask::descriptor()); - descriptors.push_back(google::protobuf::Int32Value::descriptor()); - descriptors.push_back(google::protobuf::Struct::descriptor()); - descriptors.push_back(google::protobuf::Timestamp::descriptor()); - descriptors.push_back(google::protobuf::Value::descriptor()); - ResetTypeInfo(descriptors); - } -}; - -INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest, - ProtoStreamObjectWriterAnyTest, - ::testing::Values( - testing::USE_TYPE_RESOLVER)); - -TEST_P(ProtoStreamObjectWriterAnyTest, AnyRenderSuccess) { - AnyOut any; - google::protobuf::Any* any_type = any.mutable_any(); - any_type->set_type_url("type.googleapis.com/google.protobuf.DoubleValue"); - google::protobuf::DoubleValue d; - d.set_value(40.2); - any_type->set_value(d.SerializeAsString()); - - ow_->StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/google.protobuf.DoubleValue") - ->RenderDouble("value", 40.2) - ->EndObject() - ->EndObject(); - CheckOutput(any); -} - -TEST_P(ProtoStreamObjectWriterAnyTest, RecursiveAny) { - AnyOut out; - ::google::protobuf::Any* any = out.mutable_any(); - any->set_type_url("type.googleapis.com/google.protobuf.Any"); - - ::google::protobuf::Any nested_any; - nested_any.set_type_url( - "type.googleapis.com/proto_util_converter.testing.AnyM"); - - AnyM m; - m.set_foo("foovalue"); - nested_any.set_value(m.SerializeAsString()); - - any->set_value(nested_any.SerializeAsString()); - - ow_->StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") - ->StartObject("value") - ->RenderString("@type", - "type.googleapis.com/proto_util_converter.testing.AnyM") - ->RenderString("foo", "foovalue") - ->EndObject() - ->EndObject() - ->EndObject(); - CheckOutput(out, 112); -} - -TEST_P(ProtoStreamObjectWriterAnyTest, DoubleRecursiveAny) { - AnyOut out; - ::google::protobuf::Any* any = out.mutable_any(); - any->set_type_url("type.googleapis.com/google.protobuf.Any"); - - ::google::protobuf::Any nested_any; - nested_any.set_type_url("type.googleapis.com/google.protobuf.Any"); - - ::google::protobuf::Any second_nested_any; - second_nested_any.set_type_url( - "type.googleapis.com/proto_util_converter.testing.AnyM"); - - AnyM m; - m.set_foo("foovalue"); - second_nested_any.set_value(m.SerializeAsString()); - - nested_any.set_value(second_nested_any.SerializeAsString()); - any->set_value(nested_any.SerializeAsString()); - - ow_->StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") - ->StartObject("value") - ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") - ->StartObject("value") - ->RenderString("@type", - "type.googleapis.com/proto_util_converter.testing.AnyM") - ->RenderString("foo", "foovalue") - ->EndObject() - ->EndObject() - ->EndObject() - ->EndObject(); - CheckOutput(out, 156); -} - -TEST_P(ProtoStreamObjectWriterAnyTest, TypeUrlAtEnd) { - Book book; - book.set_title("C++"); - book.set_length(1234); - book.set_content("Hello World!"); - - ::google::protobuf::Any any; - any.PackFrom(book); - - ::google::protobuf::Any outer_any; - outer_any.PackFrom(any); - - AnyOut out; - out.mutable_any()->PackFrom(outer_any); - - // Put the @type field at the end of each Any message. Parsers should - // be able to accept that. - ow_->StartObject("") - ->StartObject("any") - ->StartObject("value") - ->StartObject("value") - ->RenderString("title", "C++") - ->RenderInt32("length", 1234) - ->RenderBytes("content", "Hello World!") - ->RenderString("@type", - "type.googleapis.com/proto_util_converter.testing.Book") - ->EndObject() - ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") - ->EndObject() - ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") - ->EndObject() - ->EndObject(); - CheckOutput(out); -} - -// Same as TypeUrlAtEnd, but use temporary string values to make sure we don't -// mistakenly store absl::string_view objects pointing to invalid memory. -TEST_P(ProtoStreamObjectWriterAnyTest, TypeUrlAtEndWithTemporaryStrings) { - Book book; - book.set_title("C++"); - book.set_length(1234); - book.set_content("Hello World!"); - - ::google::protobuf::Any any; - any.PackFrom(book); - - ::google::protobuf::Any outer_any; - outer_any.PackFrom(any); - - AnyOut out; - out.mutable_any()->PackFrom(outer_any); - - std::string name, value; - // Put the @type field at the end of each Any message. Parsers should - // be able to accept that. - ow_->StartObject("")->StartObject("any"); - { - ow_->StartObject("value"); - { - ow_->StartObject("value"); - { - name = "title"; - value = "C++"; - ow_->RenderString(name, value); - name = "length"; - ow_->RenderInt32(name, 1234); - name = "content"; - value = "Hello World!"; - ow_->RenderBytes(name, value); - name = "@type"; - value = "type.googleapis.com/proto_util_converter.testing.Book"; - ow_->RenderString(name, value); - } - ow_->EndObject(); - - name = "@type"; - value = "type.googleapis.com/google.protobuf.Any"; - ow_->RenderString(name, value); - } - ow_->EndObject(); - - name = "@type"; - value = "type.googleapis.com/google.protobuf.Any"; - ow_->RenderString(name, value); - } - ow_->EndObject()->EndObject(); - CheckOutput(out); -} - -TEST_P(ProtoStreamObjectWriterAnyTest, EmptyAnyFromEmptyObject) { - AnyOut out; - out.mutable_any(); - - EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); - - ow_->StartObject("")->StartObject("any")->EndObject()->EndObject(); - - CheckOutput(out, 2); -} - -TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails1) { - AnyOut any; - - EXPECT_CALL( - listener_, - InvalidValue(_, absl::string_view("Any"), - absl::string_view("Missing @type for any field in " - "proto_util_converter.testing.AnyOut"))); - - ow_->StartObject("") - ->StartObject("any") - ->StartObject("another") - ->EndObject() - ->EndObject() - ->EndObject(); - CheckOutput(any); -} - -TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails2) { - AnyOut any; - - EXPECT_CALL( - listener_, - InvalidValue(_, absl::string_view("Any"), - absl::string_view("Missing @type for any field in " - "proto_util_converter.testing.AnyOut"))); - - ow_->StartObject("") - ->StartObject("any") - ->StartList("another") - ->EndObject() - ->EndObject() - ->EndObject(); - CheckOutput(any); -} - -TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails3) { - AnyOut any; - - EXPECT_CALL( - listener_, - InvalidValue(_, absl::string_view("Any"), - absl::string_view("Missing @type for any field in " - "proto_util_converter.testing.AnyOut"))); - - ow_->StartObject("") - ->StartObject("any") - ->RenderString("value", "somevalue") - ->EndObject() - ->EndObject(); - CheckOutput(any); -} - -TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithInvalidTypeUrlFails) { - AnyOut any; - - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("Any"), - absl::string_view("Invalid type URL, type URLs must be of the form " - "'type.googleapis.com/', got: " - "type.other.com/some.Type"))); - - ow_->StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.other.com/some.Type") - ->RenderDouble("value", 40.2) - ->EndObject() - ->EndObject(); - CheckOutput(any); -} - -TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithUnknownTypeFails) { - AnyOut any; - - EXPECT_CALL(listener_, - InvalidValue(_, absl::string_view("Any"), - absl::string_view( - "Invalid type URL, unknown type: some.Type"))); - ow_->StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/some.Type") - ->RenderDouble("value", 40.2) - ->EndObject() - ->EndObject(); - CheckOutput(any); -} - -TEST_P(ProtoStreamObjectWriterAnyTest, AnyIncorrectInputTypeFails) { - AnyOut any; - - EXPECT_CALL( - listener_, - InvalidValue(_, - absl::string_view("type.googleapis.com/google.protobuf.Any"), - absl::string_view("1"))); - ow_->StartObject("")->RenderInt32("any", 1)->EndObject(); - CheckOutput(any); -} - -TEST_P(ProtoStreamObjectWriterAnyTest, AnyAcceptsNull) { - AnyOut any; - - EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); - ow_->StartObject("")->RenderNull("any")->EndObject(); - CheckOutput(any); -} - -TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypeErrorTest) { - EXPECT_CALL(listener_, - InvalidValue(_, absl::string_view("Any"), - absl::string_view("Illegal timestamp format; " - "timestamps must end with " - "'Z' or have a valid " - "timezone offset."))); - - AnyOut any; - google::protobuf::Any* any_type = any.mutable_any(); - any_type->set_type_url("type.googleapis.com/google.protobuf.Timestamp"); - - ow_->StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/google.protobuf.Timestamp") - ->RenderString("value", "") - ->EndObject() - ->EndObject(); - CheckOutput(any); -} - -// Test the following case: -// -// { -// "any": { -// "@type": "type.googleapis.com/google.protobuf.Value", -// "value": "abc" -// } -// } -TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithNestedPrimitiveValue) { - AnyOut out; - ::google::protobuf::Any* any = out.mutable_any(); - - ::google::protobuf::Value value; - value.set_string_value("abc"); - any->PackFrom(value); - - ow_->StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") - ->RenderString("value", "abc") - ->EndObject() - ->EndObject(); - CheckOutput(out); -} - -// Test the following case: -// -// { -// "any": { -// "@type": "type.googleapis.com/google.protobuf.Value", -// "value": { -// "foo": "abc" -// } -// } -// } -TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithNestedObjectValue) { - AnyOut out; - ::google::protobuf::Any* any = out.mutable_any(); - - ::google::protobuf::Value value; - (*value.mutable_struct_value()->mutable_fields())["foo"].set_string_value( - "abc"); - any->PackFrom(value); - - ow_->StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") - ->StartObject("value") - ->RenderString("foo", "abc") - ->EndObject() - ->EndObject() - ->EndObject(); - CheckOutput(out); -} - -// Test the following case: -// -// { -// "any": { -// "@type": "type.googleapis.com/google.protobuf.Value", -// "value": ["hello"], -// } -// } -TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithNestedArrayValue) { - AnyOut out; - ::google::protobuf::Any* any = out.mutable_any(); - - ::google::protobuf::Value value; - value.mutable_list_value()->add_values()->set_string_value("hello"); - any->PackFrom(value); - - ow_->StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") - ->StartList("value") - ->RenderString("", "hello") - ->EndList() - ->EndObject() - ->EndObject() - ->EndObject(); - CheckOutput(out); -} - -// Test the following case: -// -// { -// "any": { -// "@type": "type.googleapis.com/google.protobuf.Value", -// "not_value": "" -// } -// } -TEST_P(ProtoStreamObjectWriterAnyTest, - AnyWellKnownTypesNoValueFieldForPrimitive) { - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("Any"), - absl::string_view("Expect a \"value\" field for well-known types."))); - AnyOut any; - google::protobuf::Any* any_type = any.mutable_any(); - any_type->set_type_url("type.googleapis.com/google.protobuf.Value"); - - ow_->StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") - ->RenderString("not_value", "") - ->EndObject() - ->EndObject(); - CheckOutput(any); -} - -// Test the following case: -// -// { -// "any": { -// "@type": "type.googleapis.com/google.protobuf.Value", -// "not_value": {} -// } -// } -TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesNoValueFieldForObject) { - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("Any"), - absl::string_view("Expect a \"value\" field for well-known types."))); - AnyOut any; - google::protobuf::Any* any_type = any.mutable_any(); - any_type->set_type_url("type.googleapis.com/google.protobuf.Value"); - - ow_->StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") - ->StartObject("not_value") - ->EndObject() - ->EndObject() - ->EndObject(); - CheckOutput(any); -} - -// Test the following case: -// -// { -// "any": { -// "@type": "type.googleapis.com/google.protobuf.Value", -// "not_value": [], -// } -// } -TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesNoValueFieldForArray) { - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("Any"), - absl::string_view("Expect a \"value\" field for well-known types."))); - AnyOut any; - google::protobuf::Any* any_type = any.mutable_any(); - any_type->set_type_url("type.googleapis.com/google.protobuf.Value"); - - ow_->StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") - ->StartList("not_value") - ->EndList() - ->EndObject() - ->EndObject() - ->EndObject(); - CheckOutput(any); -} - -// Test the following case: -// -// { -// "any": { -// "@type": "type.googleapis.com/google.protobuf.Struct", -// "value": "", -// } -// } -TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesExpectObjectForStruct) { - EXPECT_CALL(listener_, - InvalidValue(_, absl::string_view("Any"), - absl::string_view("Expect a JSON object."))); - AnyOut any; - google::protobuf::Any* any_type = any.mutable_any(); - any_type->set_type_url("type.googleapis.com/google.protobuf.Struct"); - - ow_->StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/google.protobuf.Struct") - ->RenderString("value", "") - ->EndObject() - ->EndObject(); - CheckOutput(any); -} - -// Test the following case: -// -// { -// "any": { -// "@type": "type.googleapis.com/google.protobuf.Any", -// "value": "", -// } -// } -TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesExpectObjectForAny) { - EXPECT_CALL(listener_, - InvalidValue(_, absl::string_view("Any"), - absl::string_view("Expect a JSON object."))); - AnyOut any; - google::protobuf::Any* any_type = any.mutable_any(); - any_type->set_type_url("type.googleapis.com/google.protobuf.Any"); - - ow_->StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") - ->RenderString("value", "") - ->EndObject() - ->EndObject(); - CheckOutput(any); -} - -// { -// "any": { -// "@type": "type.googleapis.com/google.protobuf.Any", -// "value": null -// } -// } -TEST_P(ProtoStreamObjectWriterAnyTest, AnyInAnyAcceptsNull) { - AnyOut out; - google::protobuf::Any empty; - out.mutable_any()->PackFrom(empty); - - EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); - ow_->StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") - ->RenderNull("value") - ->EndObject() - ->EndObject(); - CheckOutput(out); -} - -// { -// "any": { -// "@type": "type.googleapis.com/google.protobuf.Timestamp", -// "value": null -// } -// } -TEST_P(ProtoStreamObjectWriterAnyTest, TimestampInAnyAcceptsNull) { - AnyOut out; - google::protobuf::Timestamp empty; - out.mutable_any()->PackFrom(empty); - - EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); - ow_->StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/google.protobuf.Timestamp") - ->RenderNull("value") - ->EndObject() - ->EndObject(); - CheckOutput(out); -} - -// { -// "any": { -// "@type": "type.googleapis.com/google.protobuf.Duration", -// "value": null -// } -// } -TEST_P(ProtoStreamObjectWriterAnyTest, DurationInAnyAcceptsNull) { - AnyOut out; - google::protobuf::Duration empty; - out.mutable_any()->PackFrom(empty); - - EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); - ow_->StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/google.protobuf.Duration") - ->RenderNull("value") - ->EndObject() - ->EndObject(); - CheckOutput(out); -} - -// { -// "any": { -// "@type": "type.googleapis.com/google.protobuf.FieldMask", -// "value": null -// } -// } -TEST_P(ProtoStreamObjectWriterAnyTest, FieldMaskInAnyAcceptsNull) { - AnyOut out; - google::protobuf::FieldMask empty; - out.mutable_any()->PackFrom(empty); - - EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); - ow_->StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/google.protobuf.FieldMask") - ->RenderNull("value") - ->EndObject() - ->EndObject(); - CheckOutput(out); -} - -// { -// "any": { -// "@type": "type.googleapis.com/google.protobuf.Int32Value", -// "value": null -// } -// } -TEST_P(ProtoStreamObjectWriterAnyTest, WrapperInAnyAcceptsNull) { - AnyOut out; - google::protobuf::Int32Value empty; - out.mutable_any()->PackFrom(empty); - - EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); - ow_->StartObject("") - ->StartObject("any") - ->RenderString("@type", "type.googleapis.com/google.protobuf.Int32Value") - ->RenderNull("value") - ->EndObject() - ->EndObject(); - CheckOutput(out); -} - -class ProtoStreamObjectWriterFieldMaskTest - : public BaseProtoStreamObjectWriterTest { - protected: - ProtoStreamObjectWriterFieldMaskTest() { - std::vector descriptors; - descriptors.push_back(FieldMaskTest::descriptor()); - descriptors.push_back(google::protobuf::FieldMask::descriptor()); - ResetTypeInfo(descriptors); - } -}; - -INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest, - ProtoStreamObjectWriterFieldMaskTest, - ::testing::Values( - testing::USE_TYPE_RESOLVER)); - -TEST_P(ProtoStreamObjectWriterFieldMaskTest, SimpleFieldMaskTest) { - FieldMaskTest expected; - expected.set_id("1"); - expected.mutable_single_mask()->add_paths("path1"); - - ow_->StartObject(""); - ow_->RenderString("id", "1"); - ow_->RenderString("single_mask", "path1"); - ow_->EndObject(); - - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterFieldMaskTest, MultipleMasksInCompactForm) { - FieldMaskTest expected; - expected.set_id("1"); - expected.mutable_single_mask()->add_paths("camel_case1"); - expected.mutable_single_mask()->add_paths("camel_case2"); - expected.mutable_single_mask()->add_paths("camel_case3"); - - ow_->StartObject(""); - ow_->RenderString("id", "1"); - ow_->RenderString("single_mask", "camelCase1,camelCase2,camelCase3"); - ow_->EndObject(); - - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterFieldMaskTest, RepeatedFieldMaskTest) { - FieldMaskTest expected; - expected.set_id("1"); - google::protobuf::FieldMask* mask = expected.add_repeated_mask(); - mask->add_paths("field1"); - mask->add_paths("field2"); - expected.add_repeated_mask()->add_paths("field3"); - - ow_->StartObject(""); - ow_->RenderString("id", "1"); - ow_->StartList("repeated_mask"); - ow_->RenderString("", "field1,field2"); - ow_->RenderString("", "field3"); - ow_->EndList(); - ow_->EndObject(); - - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterFieldMaskTest, EmptyFieldMaskTest) { - FieldMaskTest expected; - expected.set_id("1"); - - ow_->StartObject(""); - ow_->RenderString("id", "1"); - ow_->RenderString("single_mask", ""); - ow_->EndObject(); - - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterFieldMaskTest, MaskUsingApiaryStyleShouldWork) { - FieldMaskTest expected; - expected.set_id("1"); - - ow_->StartObject(""); - ow_->RenderString("id", "1"); - // Case1 - ow_->RenderString("single_mask", - "outerField(camelCase1,camelCase2,camelCase3)"); - expected.mutable_single_mask()->add_paths("outer_field.camel_case1"); - expected.mutable_single_mask()->add_paths("outer_field.camel_case2"); - expected.mutable_single_mask()->add_paths("outer_field.camel_case3"); - - ow_->StartList("repeated_mask"); - - ow_->RenderString("", "a(field1,field2)"); - google::protobuf::FieldMask* mask = expected.add_repeated_mask(); - mask->add_paths("a.field1"); - mask->add_paths("a.field2"); - - ow_->RenderString("", "a(field3)"); - mask = expected.add_repeated_mask(); - mask->add_paths("a.field3"); - - ow_->RenderString("", "a()"); - expected.add_repeated_mask(); - - ow_->RenderString("", "a(,)"); - expected.add_repeated_mask(); - - ow_->RenderString("", "a(field1(field2(field3)))"); - mask = expected.add_repeated_mask(); - mask->add_paths("a.field1.field2.field3"); - - ow_->RenderString("", "a(field1(field2(field3,field4),field5),field6)"); - mask = expected.add_repeated_mask(); - mask->add_paths("a.field1.field2.field3"); - mask->add_paths("a.field1.field2.field4"); - mask->add_paths("a.field1.field5"); - mask->add_paths("a.field6"); - - ow_->RenderString("", "a(id,field1(id,field2(field3,field4),field5),field6)"); - mask = expected.add_repeated_mask(); - mask->add_paths("a.id"); - mask->add_paths("a.field1.id"); - mask->add_paths("a.field1.field2.field3"); - mask->add_paths("a.field1.field2.field4"); - mask->add_paths("a.field1.field5"); - mask->add_paths("a.field6"); - - ow_->RenderString("", "a(((field3,field4)))"); - mask = expected.add_repeated_mask(); - mask->add_paths("a.field3"); - mask->add_paths("a.field4"); - - ow_->EndList(); - ow_->EndObject(); - - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterFieldMaskTest, MoreCloseThanOpenParentheses) { - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.FieldMask"), - absl::string_view("Field 'single_mask', Invalid FieldMask 'a(b,c))'. " - "Cannot find matching '(' for all ')'."))); - - ow_->StartObject(""); - ow_->RenderString("id", "1"); - ow_->RenderString("single_mask", "a(b,c))"); - ow_->EndObject(); -} - -TEST_P(ProtoStreamObjectWriterFieldMaskTest, MoreOpenThanCloseParentheses) { - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.FieldMask"), - absl::string_view( - "Field 'single_mask', Invalid FieldMask 'a(((b,c)'. Cannot " - "find matching ')' for all '('."))); - - ow_->StartObject(""); - ow_->RenderString("id", "1"); - ow_->RenderString("single_mask", "a(((b,c)"); - ow_->EndObject(); -} - -TEST_P(ProtoStreamObjectWriterFieldMaskTest, PathWithMapKeyShouldWork) { - FieldMaskTest expected; - expected.mutable_single_mask()->add_paths("path.to.map[\"key1\"]"); - expected.mutable_single_mask()->add_paths( - "path.to.map[\"e\\\"[]][scape\\\"\"]"); - expected.mutable_single_mask()->add_paths("path.to.map[\"key2\"]"); - - ow_->StartObject(""); - ow_->RenderString("single_mask", - "path.to.map[\"key1\"],path.to.map[\"e\\\"[]][scape\\\"\"]," - "path.to.map[\"key2\"]"); - ow_->EndObject(); - - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterFieldMaskTest, - MapKeyMustBeAtTheEndOfAPathSegment) { - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.FieldMask"), - absl::string_view( - "Field 'single_mask', Invalid FieldMask " - "'path.to.map[\"key1\"]a,path.to.map[\"key2\"]'. " - "Map keys should be at the end of a path segment."))); - - ow_->StartObject(""); - ow_->RenderString("single_mask", - "path.to.map[\"key1\"]a,path.to.map[\"key2\"]"); - ow_->EndObject(); -} - -TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyMustEnd) { - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.FieldMask"), - absl::string_view("Field 'single_mask', Invalid FieldMask " - "'path.to.map[\"key1\"'. Map keys should be " - "represented as [\"some_key\"]."))); - - ow_->StartObject(""); - ow_->RenderString("single_mask", "path.to.map[\"key1\""); - ow_->EndObject(); -} - -TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyMustBeEscapedCorrectly) { - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("type.googleapis.com/google.protobuf.FieldMask"), - absl::string_view("Field 'single_mask', Invalid FieldMask " - "'path.to.map[\"ke\"y1\"]'. Map keys should be " - "represented as [\"some_key\"]."))); - - ow_->StartObject(""); - ow_->RenderString("single_mask", "path.to.map[\"ke\"y1\"]"); - ow_->EndObject(); -} - -TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyCanContainAnyChars) { - FieldMaskTest expected; - expected.mutable_single_mask()->add_paths( - // \xE5\xAD\x99 is the UTF-8 byte sequence for chinese character 孙. - // We cannot embed non-ASCII characters in the code directly because - // some windows compilers will try to interpret them using the system's - // current encoding and end up with invalid UTF-8 byte sequence. - "path.to.map[\"(),[],\\\"'!@#$%^&*123_|War\xE5\xAD\x99,./?><\\\\\"]"); - expected.mutable_single_mask()->add_paths("path.to.map[\"key2\"]"); - - ow_->StartObject(""); - ow_->RenderString( - "single_mask", - "path.to.map[\"(),[],\\\"'!@#$%^&*123_|War\xE5\xAD\x99,./?><\\\\\"]," - "path.to.map[\"key2\"]"); - ow_->EndObject(); - - CheckOutput(expected); -} - -TEST_P(ProtoStreamObjectWriterFieldMaskTest, FieldMaskAcceptsNull) { - FieldMaskTest expected; - EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); - ow_->StartObject("")->RenderNull("single_mask")->EndObject(); - CheckOutput(expected); -} - -class ProtoStreamObjectWriterWrappersTest - : public BaseProtoStreamObjectWriterTest { - protected: - ProtoStreamObjectWriterWrappersTest() { - std::vector descriptors; - descriptors.push_back(Int32Wrapper::descriptor()); - descriptors.push_back(google::protobuf::Int32Value::descriptor()); - ResetTypeInfo(descriptors); - } -}; - -INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest, - ProtoStreamObjectWriterWrappersTest, - ::testing::Values( - testing::USE_TYPE_RESOLVER)); - -TEST_P(ProtoStreamObjectWriterWrappersTest, WrapperAcceptsNull) { - Int32Wrapper wrapper; - EXPECT_CALL(listener_, InvalidName(_, _, _)).Times(0); - ow_->StartObject("")->RenderNull("int32")->EndObject(); - CheckOutput(wrapper); -} - -class ProtoStreamObjectWriterOneOfsTest - : public BaseProtoStreamObjectWriterTest { - protected: - ProtoStreamObjectWriterOneOfsTest() { - std::vector descriptors; - descriptors.push_back(OneOfsRequest::descriptor()); - descriptors.push_back(google::protobuf::Struct::descriptor()); - ResetTypeInfo(descriptors); - } -}; - -INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest, - ProtoStreamObjectWriterOneOfsTest, - ::testing::Values( - testing::USE_TYPE_RESOLVER)); - -TEST_P(ProtoStreamObjectWriterOneOfsTest, - MultipleOneofsFailForPrimitiveTypesTest) { - EXPECT_CALL( - listener_, - InvalidValue( - _, absl::string_view("oneof"), - absl::string_view( - "oneof field 'data' is already set. Cannot set 'intData'"))); - - ow_->StartObject(""); - ow_->RenderString("strData", "blah"); - ow_->RenderString("intData", "123"); - ow_->EndObject(); -} - -TEST_P(ProtoStreamObjectWriterOneOfsTest, - MultipleOneofsFailForMessageTypesPrimitiveFirstTest) { - // Test for setting primitive oneof field first and then message field. - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("oneof"), - absl::string_view( - "oneof field 'data' is already set. " - "Cannot set 'messageData'"))); - - // JSON: { "strData": "blah", "messageData": { "dataValue": 123 } } - ow_->StartObject(""); - ow_->RenderString("strData", "blah"); - ow_->StartObject("messageData"); - ow_->RenderInt32("dataValue", 123); - ow_->EndObject(); - ow_->EndObject(); -} - -TEST_P(ProtoStreamObjectWriterOneOfsTest, - MultipleOneofsFailForMessageTypesMessageFirstTest) { - // Test for setting message oneof field first and then primitive field. - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("oneof"), - absl::string_view( - "oneof field 'data' is already set. " - "Cannot set 'strData'"))); - - // JSON: { "messageData": { "dataValue": 123 }, "strData": "blah" } - ow_->StartObject(""); - ow_->StartObject("messageData"); - ow_->RenderInt32("dataValue", 123); - ow_->EndObject(); - ow_->RenderString("strData", "blah"); - ow_->EndObject(); -} - -TEST_P(ProtoStreamObjectWriterOneOfsTest, - MultipleOneofsFailForStructTypesPrimitiveFirstTest) { - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("oneof"), - absl::string_view( - "oneof field 'data' is already set. " - "Cannot set 'structData'"))); - - // JSON: { "strData": "blah", "structData": { "a": "b" } } - ow_->StartObject(""); - ow_->RenderString("strData", "blah"); - ow_->StartObject("structData"); - ow_->RenderString("a", "b"); - ow_->EndObject(); - ow_->EndObject(); -} - -TEST_P(ProtoStreamObjectWriterOneOfsTest, - MultipleOneofsFailForStructTypesStructFirstTest) { - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("oneof"), - absl::string_view( - "oneof field 'data' is already set. " - "Cannot set 'strData'"))); - - // JSON: { "structData": { "a": "b" }, "strData": "blah" } - ow_->StartObject(""); - ow_->StartObject("structData"); - ow_->RenderString("a", "b"); - ow_->EndObject(); - ow_->RenderString("strData", "blah"); - ow_->EndObject(); -} - -TEST_P(ProtoStreamObjectWriterOneOfsTest, - MultipleOneofsFailForStructValueTypesTest) { - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("oneof"), - absl::string_view( - "oneof field 'data' is already set. " - "Cannot set 'valueData'"))); - - // JSON: { "messageData": { "dataValue": 123 }, "valueData": { "a": "b" } } - ow_->StartObject(""); - ow_->StartObject("messageData"); - ow_->RenderInt32("dataValue", 123); - ow_->EndObject(); - ow_->StartObject("valueData"); - ow_->RenderString("a", "b"); - ow_->EndObject(); - ow_->EndObject(); -} - -TEST_P(ProtoStreamObjectWriterOneOfsTest, - MultipleOneofsFailForWellKnownTypesPrimitiveFirstTest) { - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("oneof"), - absl::string_view( - "oneof field 'data' is already set. " - "Cannot set 'tsData'"))); - - // JSON: { "intData": 123, "tsData": "1970-01-02T01:00:00.000Z" } - ow_->StartObject(""); - ow_->RenderInt32("intData", 123); - ow_->RenderString("tsData", "1970-01-02T01:00:00.000Z"); - ow_->EndObject(); -} - -TEST_P(ProtoStreamObjectWriterOneOfsTest, - MultipleOneofsFailForWellKnownTypesWktFirstTest) { - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("oneof"), - absl::string_view( - "oneof field 'data' is already set. " - "Cannot set 'intData'"))); - - // JSON: { "tsData": "1970-01-02T01:00:00.000Z", "intData": 123 } - ow_->StartObject(""); - ow_->RenderString("tsData", "1970-01-02T01:00:00.000Z"); - ow_->RenderInt32("intData", 123); - ow_->EndObject(); -} - -TEST_P(ProtoStreamObjectWriterOneOfsTest, - MultipleOneofsFailForWellKnownTypesAndMessageTest) { - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("oneof"), - absl::string_view( - "oneof field 'data' is already set. " - "Cannot set 'messageData'"))); - - // JSON: { "tsData": "1970-01-02T01:00:00.000Z", - // "messageData": { "dataValue": 123 } } - ow_->StartObject(""); - ow_->RenderString("tsData", "1970-01-02T01:00:00.000Z"); - ow_->StartObject("messageData"); - ow_->RenderInt32("dataValue", 123); - ow_->EndObject(); - ow_->EndObject(); -} - -TEST_P(ProtoStreamObjectWriterOneOfsTest, - MultipleOneofsFailForOneofWithinAnyTest) { - EXPECT_CALL(listener_, InvalidValue(_, absl::string_view("oneof"), - absl::string_view( - "oneof field 'data' is already set. " - "Cannot set 'intData'"))); - - // JSON: - // { "anyData": - // { "@type": - // "type.googleapis.com/proto_util_converter.testing.oneofs.OneOfsRequest", - // "strData": "blah", - // "intData": 123 - // } - // } - ow_->StartObject(""); - ow_->StartObject("anyData"); - ow_->RenderString( - "@type", - "type.googleapis.com/proto_util_converter.testing.oneofs.OneOfsRequest"); - ow_->RenderString("strData", "blah"); - ow_->RenderInt32("intData", 123); - ow_->EndObject(); - ow_->EndObject(); -} - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/util/internal/structured_objectwriter.h b/src/google/protobuf/util/internal/structured_objectwriter.h deleted file mode 100644 index 9fe59e3a3f..0000000000 --- a/src/google/protobuf/util/internal/structured_objectwriter.h +++ /dev/null @@ -1,123 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_STRUCTURED_OBJECTWRITER_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_STRUCTURED_OBJECTWRITER_H__ - -#include - -#include "absl/base/casts.h" -#include "google/protobuf/port.h" -#include "google/protobuf/util/internal/object_writer.h" - -// Must be included last. -#include "google/protobuf/port_def.inc" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -// An StructuredObjectWriter is an ObjectWriter for writing -// tree-structured data in a stream of events representing objects -// and collections. Implementation of this interface can be used to -// write an object stream to an in-memory structure, protobufs, -// JSON, XML, or any other output format desired. The ObjectSource -// interface is typically used as the source of an object stream. -// -// See JsonObjectWriter for a sample implementation of -// StructuredObjectWriter and its use. -// -// Derived classes could be thread-unsafe. -class PROTOBUF_EXPORT StructuredObjectWriter : public ObjectWriter { - public: - StructuredObjectWriter(const StructuredObjectWriter&) = delete; - StructuredObjectWriter& operator=(const StructuredObjectWriter&) = delete; - ~StructuredObjectWriter() override {} - - protected: - // A base element class for subclasses to extend, makes tracking state easier. - // - // StructuredObjectWriter behaves as a visitor. BaseElement represents a node - // in the input tree. Implementation of StructuredObjectWriter should also - // extend BaseElement to keep track of the location in the input tree. - class PROTOBUF_EXPORT BaseElement { - public: - // Takes ownership of the parent Element. - explicit BaseElement(BaseElement* parent) - : parent_(parent), - level_(parent == nullptr ? 0 : parent->level() + 1) {} - BaseElement() = delete; - BaseElement(const BaseElement&) = delete; - BaseElement& operator=(const BaseElement&) = delete; - virtual ~BaseElement() {} - - // Releases ownership of the parent and returns a pointer to it. - template - ElementType* pop() { - return google::protobuf::internal::DownCast(parent_.release()); - } - - // Returns true if this element is the root. - bool is_root() const { return parent_ == nullptr; } - - // Returns the number of hops from this element to the root element. - int level() const { return level_; } - - protected: - // Returns pointer to parent element without releasing ownership. - virtual BaseElement* parent() const { return parent_.get(); } - - private: - // Pointer to the parent Element. - std::unique_ptr parent_; - - // Number of hops to the root Element. - // The root Element has nullptr parent_ and a level_ of 0. - const int level_; - }; - - StructuredObjectWriter() {} - - // Returns the current element. Used for indentation and name overrides. - virtual BaseElement* element() = 0; - - private: - // Do not add any data members to this class. -}; - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google - -#include "google/protobuf/port_undef.inc" - -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_STRUCTURED_OBJECTWRITER_H__ diff --git a/src/google/protobuf/util/internal/testdata/anys.proto b/src/google/protobuf/util/internal/testdata/anys.proto deleted file mode 100644 index b6fc3f6ce8..0000000000 --- a/src/google/protobuf/util/internal/testdata/anys.proto +++ /dev/null @@ -1,118 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package proto_util_converter.testing; - -import "google/protobuf/any.proto"; -import "google/protobuf/duration.proto"; -import "google/protobuf/empty.proto"; -import "google/protobuf/struct.proto"; -import "google/protobuf/timestamp.proto"; -import "google/protobuf/wrappers.proto"; - -// Top-level test cases proto used by MarshallingTest. See description -// at the top of the class MarshallingTest for details on how to write -// test cases. -message AnyTestCases { - AnyWrapper empty_any = 1; - AnyWrapper type_only_any = 2; - AnyWrapper wrapper_any = 3; - AnyWrapper any_with_timestamp_value = 4; - AnyWrapper any_with_duration_value = 5; - AnyWrapper any_with_struct_value = 6; - AnyWrapper recursive_any = 7; - AnyWrapper any_with_message_value = 8; - AnyWrapper any_with_nested_message = 9; - AnyWrapper any_with_message_with_wrapper_type = 10; - AnyWrapper any_with_message_with_timestamp = 11; - AnyWrapper any_with_message_containing_map = 12; - AnyWrapper any_with_message_containing_struct = 13; - AnyWrapper any_with_message_containing_repeated_message = 14; - AnyWrapper recursive_any_with_type_field_at_end = 15; - AnyWrapper repeated_any = 16; - AnyWrapper empty_any_with_null_type_url = 17; - AnyWrapper any_with_empty = 18; - AnyWrapper any_with_default_timestamp = 19; - - google.protobuf.Any top_level_any = 50; - google.protobuf.Any top_level_any_with_type_field_at_end = 51; - google.protobuf.Any top_level_any_with_pivot_one = 52; - google.protobuf.Any top_level_any_with_pivot_two = 53; - google.protobuf.Any top_level_any_unordered = 54; -} - -message AnyWrapper { - google.protobuf.Any any = 1; -} - -// Hack to make sure the types we put into the any are included in the types. -// Real solution is to add these types to the service config. -message Imports { - google.protobuf.DoubleValue dbl = 1; - google.protobuf.Struct struct = 2; - google.protobuf.Timestamp timestamp = 3; - google.protobuf.Duration duration = 4; - google.protobuf.Int32Value i32 = 5; - google.protobuf.Empty empty = 6; - Data data = 100; -} - -message Data { - int32 attr = 1; - string str = 2; - repeated string msgs = 3; - Data nested_data = 4; - google.protobuf.Int32Value int_wrapper = 5; - google.protobuf.Timestamp time = 6; - map map_data = 7; - google.protobuf.Struct struct_data = 8; - repeated Data repeated_data = 9; - repeated google.protobuf.Any repeated_any = 10; -} - -service AnyTestService { - rpc Call(AnyTestCases) returns (AnyTestCases); - rpc Call1(Imports) returns (Imports); -} - -message AnyIn { - string something = 1; - google.protobuf.Any any = 2; -} - -message AnyOut { - google.protobuf.Any any = 1; -} - -message AnyM { - string foo = 1; -} diff --git a/src/google/protobuf/util/internal/testdata/books.proto b/src/google/protobuf/util/internal/testdata/books.proto deleted file mode 100644 index 328c5ce0d7..0000000000 --- a/src/google/protobuf/util/internal/testdata/books.proto +++ /dev/null @@ -1,251 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: sven@google.com (Sven Mawson) -// -// Sample protos for testing. - -// Some of the older enums don't use CAPITALS_WITH_UNDERSCORES for testing. -// LINT: LEGACY_NAMES -// LINT: ALLOW_GROUPS - -syntax = "proto2"; - -package proto_util_converter.testing; - -import "google/protobuf/util/internal/testdata/anys.proto"; - -// A book -message Book { - optional string title = 1; - optional Author author = 2; - optional uint32 length = 3; - optional int64 published = 4; - optional bytes content = 5; - - optional group Data = 6 { - optional uint32 year = 7; - optional string copyright = 8; - } - - message Label { - optional string key = 1; - optional string value = 2; - } - - optional Publisher publisher = 9; - repeated Label labels = 10; - - enum Type { - FICTION = 1; - KIDS = 2; - ACTION_AND_ADVENTURE = 3; - arts_and_photography = 4; - I18N_Tech = 5; - } - optional Type type = 11; - - // Useful for testing JSON snake/camel-case conversions. - optional string snake_field = 12; - - // Used to test type not found in type info. Messages defined in other files - // are not added when adding Book to type info. - optional AnyWrapper type_not_found = 13; - - // Used to test invalid value inside of primitive repeated fields. - repeated int32 primitive_repeated = 14; - - extensions 200 to 499; -} - -// A publisher of a book, tests required fields. -message Publisher { - required string name = 1; -} - -// An author of a book -message Author { - optional uint64 id = 1 [json_name = "@id"]; - optional string name = 2; - repeated string pseudonym = 3; - optional bool alive = 4; - repeated Author friend = 5; -} - -// For testing resiliency of our protostream parser. -// Field numbers of Author are reused for something else. -message BadAuthor { - optional string id = 1; // non-length-delimited to length-delimited. - repeated uint64 name = 2; // string to repeated (both length-delimited). - optional string pseudonym = 3; // Repeated to optional. - repeated bool alive = 4 [packed = true]; // Optional to repeated. -} - -// All primitive types -message Primitive { - // 32 bit numbers: - optional fixed32 fix32 = 1; - optional uint32 u32 = 2; - optional int32 i32 = 3; - optional sfixed32 sf32 = 4; - optional sint32 s32 = 5; - - // 64 bit numbers: - optional fixed64 fix64 = 6; - optional uint64 u64 = 7; - optional int64 i64 = 8; - optional sfixed64 sf64 = 9; - optional sint64 s64 = 10; - - // The other stuff. - optional string str = 11; - optional bytes bytes = 12; - optional float float = 13; - optional double double = 14; - optional bool bool = 15; - - // repeated 32 bit numbers: - repeated fixed32 rep_fix32 = 16; - repeated uint32 rep_u32 = 17; - repeated int32 rep_i32 = 18; - repeated sfixed32 rep_sf32 = 19; - repeated sint32 rep_s32 = 20; - - // repeated 64 bit numbers: - repeated fixed64 rep_fix64 = 21; - repeated uint64 rep_u64 = 22; - repeated int64 rep_i64 = 23; - repeated sfixed64 rep_sf64 = 24; - repeated sint64 rep_s64 = 25; - - // repeated other stuff: - repeated string rep_str = 26; - repeated bytes rep_bytes = 27; - repeated float rep_float = 28; - repeated double rep_double = 29; - repeated bool rep_bool = 30; -} - -// Test packed versions of all repeated primitives. -// The field numbers should match their non-packed version in Primitive message. -message PackedPrimitive { - // repeated 32 bit numbers: - repeated fixed32 rep_fix32 = 16 [packed = true]; - repeated uint32 rep_u32 = 17 [packed = true]; - repeated int32 rep_i32 = 18 [packed = true]; - repeated sfixed32 rep_sf32 = 19 [packed = true]; - repeated sint32 rep_s32 = 20 [packed = true]; - - // repeated 64 bit numbers: - repeated fixed64 rep_fix64 = 21 [packed = true]; - repeated uint64 rep_u64 = 22 [packed = true]; - repeated int64 rep_i64 = 23 [packed = true]; - repeated sfixed64 rep_sf64 = 24 [packed = true]; - repeated sint64 rep_s64 = 25 [packed = true]; - - // repeated other stuff: - repeated float rep_float = 28 [packed = true]; - repeated double rep_double = 29 [packed = true]; - repeated bool rep_bool = 30 [packed = true]; -} - -// Test extensions. -extend Book { - repeated Author more_author = 201; -} - -// Test nested extensions. -message NestedBook { - extend Book { - optional NestedBook another_book = 301; - } - // Recurse - optional Book book = 1; -} - -// For testing resiliency of our protostream parser. -// Field number of NestedBook is reused for something else. -message BadNestedBook { - repeated uint32 book = 1 [packed = true]; // Packed to optional message. -} - -// A recursively defined message. -message Cyclic { - optional int32 m_int = 1; - optional string m_str = 2; - optional Book m_book = 3; - repeated Author m_author = 5; - optional Cyclic m_cyclic = 4; -} - -// Test that two messages can have different fields mapped to the same JSON -// name. See: https://github.com/protocolbuffers/protobuf/issues/1415 -message TestJsonName1 { - optional int32 one_value = 1 [json_name = "value"]; -} -message TestJsonName2 { - optional int32 another_value = 1 [json_name = "value"]; -} - -message TestPrimitiveFieldsWithSameJsonName { - optional string val_str1 = 1; - optional string val_str_1 = 2; - - optional int32 val_int321 = 3; - optional int32 val_int32_1 = 4; - - optional uint32 val_uint321 = 5; - optional uint32 val_uint32_1 = 6; - - optional int64 val_int641 = 7; - optional int64 val_int64_1 = 8; - - optional uint64 val_uint641 = 9; - optional uint64 val_uint64_1 = 10; - - optional bool val_bool1 = 11; - optional bool val_bool_1 = 12; - - optional double val_double1 = 13; - optional double val_double_1 = 14; - - optional float val_float1 = 15; - optional float val_float_1 = 16; -} - -message TestRepeatedFieldsWithSameJsonName { - repeated string rep_str1 = 1; - repeated string rep_str_1 = 2; -} - -message TestMessageFieldsWithSameJsonName { - optional Primitive prim1 = 1; - optional Primitive prim_1 = 2; -} diff --git a/src/google/protobuf/util/internal/testdata/default_value.proto b/src/google/protobuf/util/internal/testdata/default_value.proto deleted file mode 100644 index 79ce144383..0000000000 --- a/src/google/protobuf/util/internal/testdata/default_value.proto +++ /dev/null @@ -1,170 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package proto_util_converter.testing; - -import "google/protobuf/any.proto"; -import "google/protobuf/struct.proto"; -import "google/protobuf/wrappers.proto"; - -message DefaultValueTestCases { - DoubleMessage empty_double = 1; - DoubleMessage double_with_default_value = 2; - DoubleMessage double_with_nondefault_value = 3; - DoubleMessage repeated_double = 4; - DoubleMessage nested_message = 5; - DoubleMessage repeated_nested_message = 6; - DoubleMessage double_message_with_oneof = 7; - StructMessage empty_struct = 201; - StructMessage empty_struct2 = 202; - StructMessage struct_with_null_value = 203; - StructMessage struct_with_values = 204; - StructMessage struct_with_nested_struct = 205; - StructMessage struct_with_nested_list = 206; - StructMessage struct_with_list_of_nulls = 207; - StructMessage struct_with_list_of_lists = 208; - StructMessage struct_with_list_of_structs = 209; - google.protobuf.Struct top_level_struct = 210; - ValueMessage value_wrapper_simple = 212; - ValueMessage value_wrapper_with_struct = 213; - ValueMessage value_wrapper_with_list = 214; - ListValueMessage list_value_wrapper = 215; - google.protobuf.Value top_level_value_simple = 216; - google.protobuf.Value top_level_value_with_struct = 217; - google.protobuf.Value top_level_value_with_list = 218; - google.protobuf.ListValue top_level_listvalue = 219; - AnyMessage empty_any = 301; - AnyMessage type_only_any = 302; - AnyMessage recursive_any = 303; - AnyMessage any_with_message_value = 304; - AnyMessage any_with_nested_message = 305; - AnyMessage any_with_message_containing_map = 306; - AnyMessage any_with_message_containing_struct = 307; - google.protobuf.Any top_level_any = 308; - StringtoIntMap empty_map = 401; - StringtoIntMap string_to_int = 402; - IntToStringMap int_to_string = 403; - MixedMap mixed1 = 404; - MixedMap2 mixed2 = 405; - MixedMap2 empty_mixed2 = 406; - MessageMap map_of_objects = 407; - MixedMap mixed_empty = 408; - MessageMap message_map_empty = 409; - DoubleValueMessage double_value = 501; - DoubleValueMessage double_value_default = 502; -} - -message DoubleMessage { - double double_value = 1; - repeated double repeated_double = 2; - DoubleMessage nested_message = 3; - repeated DoubleMessage repeated_nested_message = 4; - google.protobuf.DoubleValue double_wrapper = 100; - oneof value { - string str_value = 112; - int64 num_value = 113; - } -} - -message StructMessage { - google.protobuf.Struct struct = 1; -} - -message ValueMessage { - google.protobuf.Value value = 1; -} - -message ListValueMessage { - google.protobuf.ListValue shopping_list = 1; -} -message RequestMessage { - string content = 1; -} - -// A test service. -service DefaultValueTestService { - // A test method. - rpc Call(RequestMessage) returns (DefaultValueTestCases); -} - -message AnyMessage { - google.protobuf.Any any = 1; - AnyData data = 2; -} - -message AnyData { - int32 attr = 1; - string str = 2; - repeated string msgs = 3; - AnyData nested_data = 4; - map map_data = 7; - google.protobuf.Struct struct_data = 8; - repeated AnyData repeated_data = 9; -} - -message StringtoIntMap { - map map = 1; -} - -message IntToStringMap { - map map = 1; -} - -message MixedMap { - string msg = 1; - map map = 2; - int32 int_value = 3; -} - -message MixedMap2 { - enum E { - E0 = 0; - E1 = 1; - E2 = 2; - E3 = 3; - } - map map = 1; - E ee = 2; - string msg = 4; -} - -message MessageMap { - message M { - int32 inner_int = 1; - string inner_text = 2; - } - map map = 1; -} - -message DoubleValueMessage { - google.protobuf.DoubleValue double = 1; -} diff --git a/src/google/protobuf/util/internal/testdata/default_value_test.proto b/src/google/protobuf/util/internal/testdata/default_value_test.proto deleted file mode 100644 index af755d3da3..0000000000 --- a/src/google/protobuf/util/internal/testdata/default_value_test.proto +++ /dev/null @@ -1,53 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package proto_util_converter.testing; - -message DefaultValueTest { - double double_value = 1; - repeated double repeated_double = 2; - float float_value = 3; - int64 int64_value = 5; - uint64 uint64_value = 7; - int32 int32_value = 9; - uint32 uint32_value = 11; - bool bool_value = 13; - string string_value = 15; - bytes bytes_value = 17 [ctype = CORD]; - - enum EnumDefault { - ENUM_FIRST = 0; - ENUM_SECOND = 1; - ENUM_THIRD = 2; - } - EnumDefault enum_value = 18; -} diff --git a/src/google/protobuf/util/internal/testdata/field_mask.proto b/src/google/protobuf/util/internal/testdata/field_mask.proto deleted file mode 100644 index 9d2bc40043..0000000000 --- a/src/google/protobuf/util/internal/testdata/field_mask.proto +++ /dev/null @@ -1,71 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package proto_util_converter.testing; - -import "google/protobuf/field_mask.proto"; - -message NestedFieldMask { - string data = 1; - google.protobuf.FieldMask single_mask = 2; - repeated google.protobuf.FieldMask repeated_mask = 3; -} - -message FieldMaskTest { - string id = 1; - google.protobuf.FieldMask single_mask = 2; - repeated google.protobuf.FieldMask repeated_mask = 3; - repeated NestedFieldMask nested_mask = 4; -} - -message FieldMaskTestCases { - FieldMaskWrapper single_mask = 1; - FieldMaskWrapper multiple_mask = 2; - FieldMaskWrapper snake_camel = 3; - FieldMaskWrapper empty_field = 4; - FieldMaskWrapper apiary_format1 = 5; - FieldMaskWrapper apiary_format2 = 6; - FieldMaskWrapper apiary_format3 = 7; - FieldMaskWrapper map_key1 = 8; - FieldMaskWrapper map_key2 = 9; - FieldMaskWrapper map_key3 = 10; - FieldMaskWrapper map_key4 = 11; - FieldMaskWrapper map_key5 = 12; -} - -message FieldMaskWrapper { - google.protobuf.FieldMask mask = 1; -} - -service FieldMaskTestService { - rpc Call(FieldMaskTestCases) returns (FieldMaskTestCases); -} diff --git a/src/google/protobuf/util/internal/testdata/maps.proto b/src/google/protobuf/util/internal/testdata/maps.proto deleted file mode 100644 index a9fdbe63af..0000000000 --- a/src/google/protobuf/util/internal/testdata/maps.proto +++ /dev/null @@ -1,148 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package proto_util_converter.testing; - -import "google/protobuf/any.proto"; - -// Top-level test cases proto used by MarshallingTest. See description -// at the top of the class MarshallingTest for details on how to write -// test cases. -message MapsTestCases { - EmptyMap empty_map = 1; - StringtoInt string_to_int = 2; - IntToString int_to_string = 3; - Mixed1 mixed1 = 4; - Mixed2 mixed2 = 5; - MapOfObjects map_of_objects = 6; - - // Empty key tests - StringtoInt empty_key_string_to_int1 = 7; - StringtoInt empty_key_string_to_int2 = 8; - StringtoInt empty_key_string_to_int3 = 9; - BoolToString empty_key_bool_to_string = 10; - IntToString empty_key_int_to_string = 11; - Mixed1 empty_key_mixed = 12; - MapOfObjects empty_key_map_objects = 13; -} - -message EmptyMap { - map map = 1; -} - -message StringtoInt { - map map = 1; -} - -message IntToString { - map map = 1; -} - -message BoolToString { - map map = 1; -} - -message Mixed1 { - string msg = 1; - map map = 2; -} - -message Mixed2 { - enum E { - E0 = 0; - E1 = 1; - E2 = 2; - E3 = 3; - } - map map = 1; - E ee = 2; -} - -message MapOfObjects { - message M { - string inner_text = 1; - } - map map = 1; -} - -message DummyRequest {} - -service MapsTestService { - rpc Call(DummyRequest) returns (MapsTestCases); -} - -message MapIn { - string other = 1; - repeated string things = 2; - map map_input = 3; - map map_any = 4; -} - -message MapOut { - map map1 = 1; - map map2 = 2; - map map3 = 3; - map map4 = 5; - string bar = 4; -} - -// A message with exactly the same wire representation as MapOut, but using -// repeated message fields instead of map fields. We use this message to test -// the wire-format compatibility of the JSON transcoder (e.g., whether it -// handles missing keys correctly). -message MapOutWireFormat { - message Map1Entry { - string key = 1; - MapM value = 2; - } - repeated Map1Entry map1 = 1; - message Map2Entry { - string key = 1; - MapOut value = 2; - } - repeated Map2Entry map2 = 2; - message Map3Entry { - int32 key = 1; - string value = 2; - } - repeated Map3Entry map3 = 3; - message Map4Entry { - bool key = 1; - string value = 2; - } - repeated Map4Entry map4 = 5; - string bar = 4; -} - -message MapM { - string foo = 1; -} diff --git a/src/google/protobuf/util/internal/testdata/oneofs.proto b/src/google/protobuf/util/internal/testdata/oneofs.proto deleted file mode 100644 index 7706af0bde..0000000000 --- a/src/google/protobuf/util/internal/testdata/oneofs.proto +++ /dev/null @@ -1,77 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Proto to test proto3 oneofs. -syntax = "proto3"; - -package proto_util_converter.testing.oneofs; - -import "google/protobuf/any.proto"; -import "google/protobuf/struct.proto"; -import "google/protobuf/timestamp.proto"; - -message OneOfsRequest { - string value = 1; - oneof data { - string str_data = 2; - int32 int_data = 3; - // Simple message - Data message_data = 4; - MoreData more_data = 5; - // Well known types - google.protobuf.Struct struct_data = 6; - google.protobuf.Value value_data = 7; - google.protobuf.ListValue list_value_data = 8; - google.protobuf.Timestamp ts_data = 9; - } - google.protobuf.Any any_data = 19; -} - -message RequestWithSimpleOneof { - string value = 1; - oneof data { - string str_data = 2; - int32 int_data = 3; - Data message_data = 4; - MoreData more_data = 5; - } -} - -message Data { - int32 data_value = 1; -} - -message MoreData { - string str_value = 1; -} - -message Response { - string value = 1; -} diff --git a/src/google/protobuf/util/internal/testdata/proto3.proto b/src/google/protobuf/util/internal/testdata/proto3.proto deleted file mode 100644 index 01434b024a..0000000000 --- a/src/google/protobuf/util/internal/testdata/proto3.proto +++ /dev/null @@ -1,42 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package proto_util_converter.testing; - -message Proto3Message { - enum NestedEnum { - FOO = 0; - BAR = 1; - BAZ = 2; - } - NestedEnum enum_value = 1; -} diff --git a/src/google/protobuf/util/internal/testdata/struct.proto b/src/google/protobuf/util/internal/testdata/struct.proto deleted file mode 100644 index a50ea87f3d..0000000000 --- a/src/google/protobuf/util/internal/testdata/struct.proto +++ /dev/null @@ -1,117 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package proto_util_converter.testing; - -import "google/protobuf/struct.proto"; - -message StructTestCases { - StructWrapper empty_value = 1; - StructWrapper empty_value2 = 2; - StructWrapper null_value = 3; - StructWrapper simple_struct = 4; - StructWrapper longer_struct = 5; - StructWrapper struct_with_nested_struct = 6; - StructWrapper struct_with_nested_list = 7; - StructWrapper struct_with_list_of_nulls = 8; - StructWrapper struct_with_list_of_lists = 9; - StructWrapper struct_with_list_of_structs = 10; - StructWrapper struct_with_empty_list = 11; - StructWrapper struct_with_list_with_empty_struct = 12; - google.protobuf.Struct top_level_struct = 13; - google.protobuf.Struct top_level_struct_with_empty_list = 14; - google.protobuf.Struct top_level_struct_with_list_with_empty_struct = 15; - ValueWrapper value_wrapper_simple = 16; - ValueWrapper value_wrapper_with_struct = 17; - ValueWrapper value_wrapper_with_list = 18; - ValueWrapper value_wrapper_with_empty_list = 19; - ValueWrapper value_wrapper_with_list_with_empty_struct = 20; - ListValueWrapper list_value_wrapper = 21; - ListValueWrapper list_value_wrapper_with_empty_list = 22; - ListValueWrapper list_value_wrapper_with_list_with_empty_struct = 23; - google.protobuf.Value top_level_value_simple = 24; - google.protobuf.Value top_level_value_with_struct = 25; - google.protobuf.Value top_level_value_with_list = 26; - google.protobuf.Value top_level_value_with_empty_list = 27; - google.protobuf.Value top_level_value_with_list_with_empty_struct = 28; - google.protobuf.ListValue top_level_listvalue = 29; - google.protobuf.ListValue top_level_empty_listvalue = 30; - google.protobuf.ListValue top_level_listvalue_with_empty_struct = 31; - RepeatedValueWrapper repeated_value = 32; - RepeatedValueWrapper repeated_value_nested_list = 33; - RepeatedValueWrapper repeated_value_nested_list2 = 34; - RepeatedValueWrapper repeated_value_nested_list3 = 35; - RepeatedListValueWrapper repeated_listvalue = 36; - MapOfStruct map_of_struct = 37; - MapOfStruct map_of_struct_value = 38; - MapOfStruct map_of_listvalue = 39; -} - -message StructWrapper { - google.protobuf.Struct struct = 1; -} - -message ValueWrapper { - google.protobuf.Value value = 1; -} - -message RepeatedValueWrapper { - repeated google.protobuf.Value values = 1; -} - -message ListValueWrapper { - google.protobuf.ListValue shopping_list = 1; -} - -message RepeatedListValueWrapper { - repeated google.protobuf.ListValue dimensions = 1; -} - -message MapOfStruct { - map struct_map = 1; - map value_map = 2; - map listvalue_map = 3; -} - -// Hack to test return types with Struct as top-level message. Struct typers -// cannot be directly used in API requests. Hence using Dummy as request type. -message Dummy { - string text = 1; -} - -service StructTestService { - rpc Call(Dummy) returns (StructTestCases); -} - -message StructType { - google.protobuf.Struct object = 1; -} diff --git a/src/google/protobuf/util/internal/testdata/timestamp_duration.proto b/src/google/protobuf/util/internal/testdata/timestamp_duration.proto deleted file mode 100644 index 8e87bdd2fa..0000000000 --- a/src/google/protobuf/util/internal/testdata/timestamp_duration.proto +++ /dev/null @@ -1,80 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package proto_util_converter.testing; - -import "google/protobuf/duration.proto"; -import "google/protobuf/timestamp.proto"; - -message TimestampDurationTestCases { - // Timestamp tests - TimeStampType epoch = 1; - TimeStampType epoch2 = 2; - TimeStampType mintime = 3; - TimeStampType maxtime = 4; - TimeStampType timeval1 = 5; - TimeStampType timeval2 = 6; - TimeStampType timeval3 = 7; - TimeStampType timeval4 = 8; - TimeStampType timeval5 = 9; - TimeStampType timeval6 = 10; - TimeStampType timeval7 = 11; - google.protobuf.Timestamp timeval8 = 12; - - // Duration tests - DurationType zero_duration = 101; - DurationType min_duration = 102; - DurationType max_duration = 103; - DurationType duration1 = 104; - DurationType duration2 = 105; - DurationType duration3 = 106; - DurationType duration4 = 107; - google.protobuf.Duration duration5 = 108; -} - -message TimeStampType { - google.protobuf.Timestamp timestamp = 1; -} - -message DurationType { - google.protobuf.Duration duration = 1; -} - -service TimestampDurationTestService { - rpc Call(TimestampDurationTestCases) returns (TimestampDurationTestCases); -} - -message TimestampDuration { - google.protobuf.Timestamp ts = 1; - google.protobuf.Duration dur = 2; - repeated google.protobuf.Timestamp rep_ts = 3; -} diff --git a/src/google/protobuf/util/internal/testdata/wrappers.proto b/src/google/protobuf/util/internal/testdata/wrappers.proto deleted file mode 100644 index e7a0541df4..0000000000 --- a/src/google/protobuf/util/internal/testdata/wrappers.proto +++ /dev/null @@ -1,100 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package proto_util_converter.testing; - -import "google/protobuf/wrappers.proto"; - -// Top-level test cases proto used by MarshallingTest. See description -// at the top of the class MarshallingTest for details on how to write -// test cases. -message WrappersTestCases { - DoubleWrapper double_wrapper = 1; - FloatWrapper float_wrapper = 2; - Int64Wrapper int64_wrapper = 3; - UInt64Wrapper uint64_wrapper = 4; - Int32Wrapper int32_wrapper = 5; - UInt32Wrapper uint32_wrapper = 6; - BoolWrapper bool_wrapper = 7; - StringWrapper string_wrapper = 8; - BytesWrapper bytes_wrapper = 9; - - DoubleWrapper double_wrapper_default = 10; - FloatWrapper float_wrapper_default = 11; - Int64Wrapper int64_wrapper_default = 12; - UInt64Wrapper uint64_wrapper_default = 13; - Int32Wrapper int32_wrapper_default = 14; - UInt32Wrapper uint32_wrapper_default = 15; - BoolWrapper bool_wrapper_default = 16; - StringWrapper string_wrapper_default = 17; - BytesWrapper bytes_wrapper_default = 18; -} - -message DoubleWrapper { - google.protobuf.DoubleValue double = 1; -} - -message FloatWrapper { - google.protobuf.FloatValue float = 1; -} - -message Int64Wrapper { - google.protobuf.Int64Value int64 = 1; -} - -message UInt64Wrapper { - google.protobuf.UInt64Value uint64 = 1; -} - -message Int32Wrapper { - google.protobuf.Int32Value int32 = 1; -} - -message UInt32Wrapper { - google.protobuf.UInt32Value uint32 = 1; -} - -message BoolWrapper { - google.protobuf.BoolValue bool = 1; -} - -message StringWrapper { - google.protobuf.StringValue string = 1; -} - -message BytesWrapper { - google.protobuf.BytesValue bytes = 1; -} - -service WrappersTestService { - rpc Call(WrappersTestCases) returns (WrappersTestCases); -} diff --git a/src/google/protobuf/util/internal/type_info.cc b/src/google/protobuf/util/internal/type_info.cc deleted file mode 100644 index 927fb939ed..0000000000 --- a/src/google/protobuf/util/internal/type_info.cc +++ /dev/null @@ -1,176 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google/protobuf/util/internal/type_info.h" - -#include -#include - -#include "google/protobuf/type.pb.h" -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "google/protobuf/util/internal/utility.h" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -namespace { -// A TypeInfo that looks up information provided by a TypeResolver. -class TypeInfoForTypeResolver : public TypeInfo { - public: - explicit TypeInfoForTypeResolver(TypeResolver* type_resolver) - : type_resolver_(type_resolver) {} - - ~TypeInfoForTypeResolver() override { - DeleteCachedTypes(&cached_types_); - DeleteCachedTypes(&cached_enums_); - } - - absl::StatusOr ResolveTypeUrl( - absl::string_view type_url) const override { - auto it = cached_types_.find(type_url); - if (it != cached_types_.end()) { - return it->second; - } - // Stores the string value so it can be referenced using absl::string_view - // in the cached_types_ map. - const std::string& string_type_url = - *string_storage_.insert(std::string(type_url)).first; - std::unique_ptr type(new google::protobuf::Type()); - absl::Status status = - type_resolver_->ResolveMessageType(string_type_url, type.get()); - StatusOrType result = - status.ok() ? StatusOrType(type.release()) : StatusOrType(status); - cached_types_[string_type_url] = result; - return result; - } - - const google::protobuf::Type* GetTypeByTypeUrl( - absl::string_view type_url) const override { - StatusOrType result = ResolveTypeUrl(type_url); - return result.ok() ? result.value() : NULL; - } - - const google::protobuf::Enum* GetEnumByTypeUrl( - absl::string_view type_url) const override { - std::map::iterator it = - cached_enums_.find(type_url); - if (it != cached_enums_.end()) { - return it->second.ok() ? it->second.value() : NULL; - } - // Stores the string value so it can be referenced using absl::string_view - // in the cached_enums_ map. - const std::string& string_type_url = - *string_storage_.insert(std::string(type_url)).first; - std::unique_ptr enum_type( - new google::protobuf::Enum()); - absl::Status status = - type_resolver_->ResolveEnumType(string_type_url, enum_type.get()); - StatusOrEnum result = - status.ok() ? StatusOrEnum(enum_type.release()) : StatusOrEnum(status); - cached_enums_[string_type_url] = result; - return result.ok() ? result.value() : NULL; - } - - const google::protobuf::Field* FindField( - const google::protobuf::Type* type, - absl::string_view camel_case_name) const override { - auto it = indexed_types_.find(type); - const CamelCaseNameTable& camel_case_name_table = - it == indexed_types_.end() - ? PopulateNameLookupTable(type, &indexed_types_[type]) - : it->second; - - absl::string_view name = camel_case_name; - auto cc_it = camel_case_name_table.find(name); - if (cc_it != camel_case_name_table.end()) { - name = cc_it->second; - } - return FindFieldInTypeOrNull(type, name); - } - - private: - typedef absl::StatusOr StatusOrType; - typedef absl::StatusOr StatusOrEnum; - typedef std::map CamelCaseNameTable; - - template - static void DeleteCachedTypes(std::map* cached_types) { - for (typename std::map::iterator it = - cached_types->begin(); - it != cached_types->end(); ++it) { - if (it->second.ok()) { - delete it->second.value(); - } - } - } - - const CamelCaseNameTable& PopulateNameLookupTable( - const google::protobuf::Type* type, - CamelCaseNameTable* camel_case_name_table) const { - for (int i = 0; i < type->fields_size(); ++i) { - const google::protobuf::Field& field = type->fields(i); - absl::string_view existing = - camel_case_name_table->insert({field.json_name(), field.name()}) - .first->second; - if (existing != field.name()) { - GOOGLE_LOG(WARNING) << "Field '" << field.name() << "' and '" << existing - << "' map to the same camel case name '" - << field.json_name() << "'."; - } - } - return *camel_case_name_table; - } - - TypeResolver* type_resolver_; - - // Stores string values that will be referenced by StringPieces in - // cached_types_, cached_enums_. - mutable std::set string_storage_; - - mutable std::map cached_types_; - mutable std::map cached_enums_; - - mutable std::map - indexed_types_; -}; -} // namespace - -TypeInfo* TypeInfo::NewTypeInfo(TypeResolver* type_resolver) { - return new TypeInfoForTypeResolver(type_resolver); -} - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/util/internal/type_info.h b/src/google/protobuf/util/internal/type_info.h deleted file mode 100644 index 801bfba1fc..0000000000 --- a/src/google/protobuf/util/internal/type_info.h +++ /dev/null @@ -1,97 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_TYPE_INFO_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_TYPE_INFO_H__ - -#include "google/protobuf/type.pb.h" -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "google/protobuf/port.h" -#include "google/protobuf/util/type_resolver.h" - - -// Must be included last. -#include "google/protobuf/port_def.inc" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { -// Internal helper class for type resolving. Note that this class is not -// thread-safe and should only be accessed in one thread. -class PROTOBUF_EXPORT TypeInfo { - public: - TypeInfo() {} - TypeInfo(const TypeInfo&) = delete; - TypeInfo& operator=(const TypeInfo&) = delete; - virtual ~TypeInfo() {} - - // Resolves a type url into a Type. If the type url is invalid, returns - // INVALID_ARGUMENT error status. If the type url is valid but the - // corresponding type cannot be found, returns a NOT_FOUND error status. - // - // This TypeInfo class retains the ownership of the returned pointer. - virtual absl::StatusOr ResolveTypeUrl( - absl::string_view type_url) const = 0; - - // Resolves a type url into a Type. Like ResolveTypeUrl() but returns - // NULL if the type url is invalid or the type cannot be found. - // - // This TypeInfo class retains the ownership of the returned pointer. - virtual const google::protobuf::Type* GetTypeByTypeUrl( - absl::string_view type_url) const = 0; - - // Resolves a type url for an enum. Returns NULL if the type url is - // invalid or the type cannot be found. - // - // This TypeInfo class retains the ownership of the returned pointer. - virtual const google::protobuf::Enum* GetEnumByTypeUrl( - absl::string_view type_url) const = 0; - - // Looks up a field in the specified type given a CamelCase name. - virtual const google::protobuf::Field* FindField( - const google::protobuf::Type* type, - absl::string_view camel_case_name) const = 0; - - // Creates a TypeInfo object that looks up type information from a - // TypeResolver. Caller takes ownership of the returned pointer. - static TypeInfo* NewTypeInfo(TypeResolver* type_resolver); -}; - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google - -#include "google/protobuf/port_undef.inc" - -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_TYPE_INFO_H__ diff --git a/src/google/protobuf/util/internal/type_info_test_helper.cc b/src/google/protobuf/util/internal/type_info_test_helper.cc deleted file mode 100644 index e73efaea9b..0000000000 --- a/src/google/protobuf/util/internal/type_info_test_helper.cc +++ /dev/null @@ -1,132 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google/protobuf/util/internal/type_info_test_helper.h" - -#include -#include - -#include "google/protobuf/stubs/logging.h" -#include "google/protobuf/stubs/common.h" -#include "google/protobuf/descriptor.h" -#include "google/protobuf/util/internal/constants.h" -#include "google/protobuf/util/internal/default_value_objectwriter.h" -#include "google/protobuf/util/internal/protostream_objectsource.h" -#include "google/protobuf/util/internal/protostream_objectwriter.h" -#include "google/protobuf/util/internal/type_info.h" -#include "google/protobuf/util/type_resolver.h" -#include "google/protobuf/util/type_resolver_util.h" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { -namespace testing { - - -void TypeInfoTestHelper::ResetTypeInfo( - const std::vector& descriptors) { - switch (type_) { - case USE_TYPE_RESOLVER: { - const DescriptorPool* pool = descriptors[0]->file()->pool(); - for (int i = 1; i < descriptors.size(); ++i) { - GOOGLE_CHECK(pool == descriptors[i]->file()->pool()) - << "Descriptors from different pools are not supported."; - } - type_resolver_.reset( - NewTypeResolverForDescriptorPool(kTypeServiceBaseUrl, pool)); - typeinfo_.reset(TypeInfo::NewTypeInfo(type_resolver_.get())); - return; - } - } - GOOGLE_LOG(FATAL) << "Can not reach here."; -} - -void TypeInfoTestHelper::ResetTypeInfo(const Descriptor* descriptor) { - std::vector descriptors; - descriptors.push_back(descriptor); - ResetTypeInfo(descriptors); -} - -void TypeInfoTestHelper::ResetTypeInfo(const Descriptor* descriptor1, - const Descriptor* descriptor2) { - std::vector descriptors; - descriptors.push_back(descriptor1); - descriptors.push_back(descriptor2); - ResetTypeInfo(descriptors); -} - -TypeInfo* TypeInfoTestHelper::GetTypeInfo() { return typeinfo_.get(); } - -ProtoStreamObjectSource* TypeInfoTestHelper::NewProtoSource( - io::CodedInputStream* coded_input, const std::string& type_url, - ProtoStreamObjectSource::RenderOptions render_options) { - const google::protobuf::Type* type = typeinfo_->GetTypeByTypeUrl(type_url); - switch (type_) { - case USE_TYPE_RESOLVER: { - return new ProtoStreamObjectSource(coded_input, type_resolver_.get(), - *type, render_options); - } - } - GOOGLE_LOG(FATAL) << "Can not reach here."; - return nullptr; -} - -ProtoStreamObjectWriter* TypeInfoTestHelper::NewProtoWriter( - const std::string& type_url, strings::ByteSink* output, - ErrorListener* listener, const ProtoStreamObjectWriter::Options& options) { - const google::protobuf::Type* type = typeinfo_->GetTypeByTypeUrl(type_url); - switch (type_) { - case USE_TYPE_RESOLVER: { - return new ProtoStreamObjectWriter(type_resolver_.get(), *type, output, - listener, options); - } - } - GOOGLE_LOG(FATAL) << "Can not reach here."; - return nullptr; -} - -DefaultValueObjectWriter* TypeInfoTestHelper::NewDefaultValueWriter( - const std::string& type_url, ObjectWriter* writer) { - const google::protobuf::Type* type = typeinfo_->GetTypeByTypeUrl(type_url); - switch (type_) { - case USE_TYPE_RESOLVER: { - return new DefaultValueObjectWriter(type_resolver_.get(), *type, writer); - } - } - GOOGLE_LOG(FATAL) << "Can not reach here."; - return nullptr; -} - -} // namespace testing -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/util/internal/type_info_test_helper.h b/src/google/protobuf/util/internal/type_info_test_helper.h deleted file mode 100644 index 9999c2c8b8..0000000000 --- a/src/google/protobuf/util/internal/type_info_test_helper.h +++ /dev/null @@ -1,96 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_TYPE_INFO_TEST_HELPER_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_TYPE_INFO_TEST_HELPER_H__ - -#include -#include - -#include "google/protobuf/io/coded_stream.h" -#include "google/protobuf/descriptor.h" -#include "google/protobuf/util/internal/default_value_objectwriter.h" -#include "google/protobuf/util/internal/protostream_objectsource.h" -#include "google/protobuf/util/internal/protostream_objectwriter.h" -#include "google/protobuf/util/internal/type_info.h" -#include "google/protobuf/util/type_resolver.h" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { -namespace testing { - -enum TypeInfoSource { - USE_TYPE_RESOLVER, -}; - -// In the unit-tests we want to test two scenarios: one with type info from -// ServiceTypeInfo, the other with type info from TypeResolver. This class -// wraps the detail of where the type info is from and provides the same -// interface so the same unit-test code can test both scenarios. -class TypeInfoTestHelper { - public: - explicit TypeInfoTestHelper(TypeInfoSource type) : type_(type) {} - - // Creates a TypeInfo object for the given set of descriptors. - void ResetTypeInfo(const std::vector& descriptors); - - // Convenient overloads. - void ResetTypeInfo(const Descriptor* descriptor); - void ResetTypeInfo(const Descriptor* descriptor1, - const Descriptor* descriptor2); - - // Returns the TypeInfo created after ResetTypeInfo. - TypeInfo* GetTypeInfo(); - - ProtoStreamObjectSource* NewProtoSource( - io::CodedInputStream* coded_input, const std::string& type_url, - ProtoStreamObjectSource::RenderOptions render_options = {}); - - ProtoStreamObjectWriter* NewProtoWriter( - const std::string& type_url, strings::ByteSink* output, - ErrorListener* listener, const ProtoStreamObjectWriter::Options& options); - - DefaultValueObjectWriter* NewDefaultValueWriter(const std::string& type_url, - ObjectWriter* writer); - - private: - TypeInfoSource type_; - std::unique_ptr typeinfo_; - std::unique_ptr type_resolver_; -}; -} // namespace testing -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google - -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_TYPE_INFO_TEST_HELPER_H__ diff --git a/src/google/protobuf/util/internal/utility.cc b/src/google/protobuf/util/internal/utility.cc deleted file mode 100644 index c2488e8ba4..0000000000 --- a/src/google/protobuf/util/internal/utility.cc +++ /dev/null @@ -1,415 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google/protobuf/util/internal/utility.h" - -#include -#include -#include -#include -#include - -#include "google/protobuf/stubs/callback.h" -#include "google/protobuf/stubs/common.h" -#include "google/protobuf/stubs/logging.h" -#include "google/protobuf/wrappers.pb.h" -#include "google/protobuf/descriptor.pb.h" -#include "google/protobuf/descriptor.h" -#include "google/protobuf/stubs/strutil.h" -#include "absl/container/flat_hash_set.h" -#include "absl/strings/ascii.h" -#include "absl/strings/match.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/string_view.h" -#include "google/protobuf/util/internal/constants.h" - -// must be last -#include "google/protobuf/port_def.inc" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -bool GetBoolOptionOrDefault( - const RepeatedPtrField& options, - absl::string_view option_name, bool default_value) { - const google::protobuf::Option* opt = FindOptionOrNull(options, option_name); - if (opt == nullptr) { - return default_value; - } - return GetBoolFromAny(opt->value()); -} - -int64_t GetInt64OptionOrDefault( - const RepeatedPtrField& options, - absl::string_view option_name, int64_t default_value) { - const google::protobuf::Option* opt = FindOptionOrNull(options, option_name); - if (opt == nullptr) { - return default_value; - } - return GetInt64FromAny(opt->value()); -} - -double GetDoubleOptionOrDefault( - const RepeatedPtrField& options, - absl::string_view option_name, double default_value) { - const google::protobuf::Option* opt = FindOptionOrNull(options, option_name); - if (opt == nullptr) { - return default_value; - } - return GetDoubleFromAny(opt->value()); -} - -std::string GetStringOptionOrDefault( - const RepeatedPtrField& options, - absl::string_view option_name, absl::string_view default_value) { - const google::protobuf::Option* opt = FindOptionOrNull(options, option_name); - if (opt == nullptr) { - return std::string(default_value); - } - return GetStringFromAny(opt->value()); -} - -template -void ParseFromAny(const std::string& data, T* result) { - result->ParseFromString(data); -} - -// Returns a boolean value contained in Any type. -// TODO(skarvaje): Add type checking & error messages here. -bool GetBoolFromAny(const google::protobuf::Any& any) { - google::protobuf::BoolValue b; - ParseFromAny(any.value(), &b); - return b.value(); -} - -int64_t GetInt64FromAny(const google::protobuf::Any& any) { - google::protobuf::Int64Value i; - ParseFromAny(any.value(), &i); - return i.value(); -} - -double GetDoubleFromAny(const google::protobuf::Any& any) { - google::protobuf::DoubleValue i; - ParseFromAny(any.value(), &i); - return i.value(); -} - -std::string GetStringFromAny(const google::protobuf::Any& any) { - google::protobuf::StringValue s; - ParseFromAny(any.value(), &s); - return s.value(); -} - -absl::string_view GetTypeWithoutUrl(absl::string_view type_url) { - if (type_url.size() > kTypeUrlSize && type_url[kTypeUrlSize] == '/') { - return type_url.substr(kTypeUrlSize + 1); - } else { - size_t idx = type_url.rfind('/'); - if (idx != type_url.npos) { - type_url.remove_prefix(idx + 1); - } - return type_url; - } -} - -std::string GetFullTypeWithUrl(absl::string_view simple_type) { - return absl::StrCat(kTypeServiceBaseUrl, "/", simple_type); -} - -const google::protobuf::Option* FindOptionOrNull( - const RepeatedPtrField& options, - absl::string_view option_name) { - for (int i = 0; i < options.size(); ++i) { - const google::protobuf::Option& opt = options.Get(i); - if (opt.name() == option_name) { - return &opt; - } - } - return nullptr; -} - -const google::protobuf::Field* FindFieldInTypeOrNull( - const google::protobuf::Type* type, absl::string_view field_name) { - if (type != nullptr) { - for (int i = 0; i < type->fields_size(); ++i) { - const google::protobuf::Field& field = type->fields(i); - if (field.name() == field_name) { - return &field; - } - } - } - return nullptr; -} - -const google::protobuf::Field* FindJsonFieldInTypeOrNull( - const google::protobuf::Type* type, absl::string_view json_name) { - if (type != nullptr) { - for (int i = 0; i < type->fields_size(); ++i) { - const google::protobuf::Field& field = type->fields(i); - if (field.json_name() == json_name) { - return &field; - } - } - } - return nullptr; -} - -const google::protobuf::Field* FindFieldInTypeByNumberOrNull( - const google::protobuf::Type* type, int32_t number) { - if (type != nullptr) { - for (int i = 0; i < type->fields_size(); ++i) { - const google::protobuf::Field& field = type->fields(i); - if (field.number() == number) { - return &field; - } - } - } - return nullptr; -} - -const google::protobuf::EnumValue* FindEnumValueByNameOrNull( - const google::protobuf::Enum* enum_type, absl::string_view enum_name) { - if (enum_type != nullptr) { - for (int i = 0; i < enum_type->enumvalue_size(); ++i) { - const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i); - if (enum_value.name() == enum_name) { - return &enum_value; - } - } - } - return nullptr; -} - -const google::protobuf::EnumValue* FindEnumValueByNumberOrNull( - const google::protobuf::Enum* enum_type, int32_t value) { - if (enum_type != nullptr) { - for (int i = 0; i < enum_type->enumvalue_size(); ++i) { - const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i); - if (enum_value.number() == value) { - return &enum_value; - } - } - } - return nullptr; -} - -const google::protobuf::EnumValue* FindEnumValueByNameWithoutUnderscoreOrNull( - const google::protobuf::Enum* enum_type, absl::string_view enum_name) { - if (enum_type != nullptr) { - for (int i = 0; i < enum_type->enumvalue_size(); ++i) { - const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i); - std::string enum_name_without_underscore = enum_value.name(); - - // Remove underscore from the name. - enum_name_without_underscore.erase( - std::remove(enum_name_without_underscore.begin(), - enum_name_without_underscore.end(), '_'), - enum_name_without_underscore.end()); - // Make the name uppercase. - for (std::string::iterator it = enum_name_without_underscore.begin(); - it != enum_name_without_underscore.end(); ++it) { - *it = absl::ascii_toupper(*it); - } - - if (enum_name_without_underscore == enum_name) { - return &enum_value; - } - } - } - return nullptr; -} - -std::string EnumValueNameToLowerCamelCase(absl::string_view input) { - return ToCamelCase(absl::AsciiStrToLower(input)); -} - -std::string ToCamelCase(absl::string_view input) { - bool capitalize_next = false; - bool was_cap = true; - bool is_cap = false; - bool first_word = true; - std::string result; - result.reserve(input.size()); - - for (size_t i = 0; i < input.size(); ++i, was_cap = is_cap) { - is_cap = absl::ascii_isupper(input[i]); - if (input[i] == '_') { - capitalize_next = true; - if (!result.empty()) first_word = false; - continue; - } else if (first_word) { - // Consider when the current character B is capitalized, - // first word ends when: - // 1) following a lowercase: "...aB..." - // 2) followed by a lowercase: "...ABc..." - if (!result.empty() && is_cap && - (!was_cap || - (i + 1 < input.size() && absl::ascii_islower(input[i + 1])))) { - first_word = false; - result.push_back(input[i]); - } else { - result.push_back(absl::ascii_tolower(input[i])); - continue; - } - } else if (capitalize_next) { - capitalize_next = false; - if (absl::ascii_islower(input[i])) { - result.push_back(absl::ascii_toupper(input[i])); - continue; - } else { - result.push_back(input[i]); - continue; - } - } else { - result.push_back(absl::ascii_tolower(input[i])); - } - } - return result; -} - -std::string ToSnakeCase(absl::string_view input) { - bool was_not_underscore = false; // Initialize to false for case 1 (below) - bool was_not_cap = false; - std::string result; - result.reserve(input.size() << 1); - - for (size_t i = 0; i < input.size(); ++i) { - if (absl::ascii_isupper(input[i])) { - // Consider when the current character B is capitalized: - // 1) At beginning of input: "B..." => "b..." - // (e.g. "Biscuit" => "biscuit") - // 2) Following a lowercase: "...aB..." => "...a_b..." - // (e.g. "gBike" => "g_bike") - // 3) At the end of input: "...AB" => "...ab" - // (e.g. "GoogleLAB" => "google_lab") - // 4) Followed by a lowercase: "...ABc..." => "...a_bc..." - // (e.g. "GBike" => "g_bike") - if (was_not_underscore && // case 1 out - (was_not_cap || // case 2 in, case 3 out - (i + 1 < input.size() && // case 3 out - absl::ascii_islower(input[i + 1])))) { // case 4 in - // We add an underscore for case 2 and case 4. - result.push_back('_'); - } - result.push_back(absl::ascii_tolower(input[i])); - was_not_underscore = true; - was_not_cap = false; - } else { - result.push_back(input[i]); - was_not_underscore = input[i] != '_'; - was_not_cap = true; - } - } - return result; -} - -absl::flat_hash_set* well_known_types_ = nullptr; -absl::once_flag well_known_types_init_; -const char* well_known_types_name_array_[] = { - "google.protobuf.Timestamp", "google.protobuf.Duration", - "google.protobuf.DoubleValue", "google.protobuf.FloatValue", - "google.protobuf.Int64Value", "google.protobuf.UInt64Value", - "google.protobuf.Int32Value", "google.protobuf.UInt32Value", - "google.protobuf.BoolValue", "google.protobuf.StringValue", - "google.protobuf.BytesValue", "google.protobuf.FieldMask"}; - -void DeleteWellKnownTypes() { delete well_known_types_; } - -void InitWellKnownTypes() { - well_known_types_ = new absl::flat_hash_set( - std::begin(well_known_types_name_array_), - std::end(well_known_types_name_array_)); - google::protobuf::internal::OnShutdown(&DeleteWellKnownTypes); -} - -bool IsWellKnownType(const std::string& type_name) { - absl::call_once(well_known_types_init_, InitWellKnownTypes); - return well_known_types_->contains(type_name); -} - -bool IsValidBoolString(absl::string_view bool_string) { - return bool_string == "true" || bool_string == "false" || - bool_string == "1" || bool_string == "0"; -} - -bool IsMap(const google::protobuf::Field& field, - const google::protobuf::Type& type) { - return field.cardinality() == google::protobuf::Field::CARDINALITY_REPEATED && - (GetBoolOptionOrDefault(type.options(), "map_entry", false) || - GetBoolOptionOrDefault(type.options(), - "google.protobuf.MessageOptions.map_entry", - false)); -} - -bool IsMessageSetWireFormat(const google::protobuf::Type& type) { - return GetBoolOptionOrDefault(type.options(), "message_set_wire_format", - false) || - GetBoolOptionOrDefault( - type.options(), - "google.protobuf.MessageOptions.message_set_wire_format", false); -} - -std::string DoubleAsString(double value) { - if (value == std::numeric_limits::infinity()) return "Infinity"; - if (value == -std::numeric_limits::infinity()) return "-Infinity"; - if (std::isnan(value)) return "NaN"; - - return SimpleDtoa(value); -} - -std::string FloatAsString(float value) { - if (std::isfinite(value)) return SimpleFtoa(value); - return DoubleAsString(value); -} - -bool SafeStrToFloat(absl::string_view str, float* value) { - double double_value; - if (!safe_strtod(str, &double_value)) { - return false; - } - - if (std::isinf(double_value) || std::isnan(double_value)) return false; - - // Fail if the value is not representable in float. - if (double_value > std::numeric_limits::max() || - double_value < -std::numeric_limits::max()) { - return false; - } - - *value = static_cast(double_value); - return true; -} - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/util/internal/utility.h b/src/google/protobuf/util/internal/utility.h deleted file mode 100644 index 552873d6ea..0000000000 --- a/src/google/protobuf/util/internal/utility.h +++ /dev/null @@ -1,207 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_UTILITY_H__ -#define GOOGLE_PROTOBUF_UTIL_INTERNAL_UTILITY_H__ - -#include -#include -#include -#include - -#include "google/protobuf/stubs/common.h" -#include "google/protobuf/stubs/logging.h" -#include "google/protobuf/any.pb.h" -#include "google/protobuf/type.pb.h" -#include "google/protobuf/repeated_field.h" -#include "google/protobuf/stubs/strutil.h" -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/string_view.h" - - -// Must be included last. -#include "google/protobuf/port_def.inc" - -namespace google { -namespace protobuf { -namespace util { -namespace converter { - -// Size of "type.googleapis.com" -static const int64_t kTypeUrlSize = 19; - -// Finds the tech option identified by option_name. Parses the boolean value and -// returns it. -// When the option with the given name is not found, default_value is returned. -PROTOBUF_EXPORT bool GetBoolOptionOrDefault( - const RepeatedPtrField& options, - absl::string_view option_name, bool default_value); - -// Returns int64 option value. If the option isn't found, returns the -// default_value. -PROTOBUF_EXPORT int64_t GetInt64OptionOrDefault( - const RepeatedPtrField& options, - absl::string_view option_name, int64_t default_value); - -// Returns double option value. If the option isn't found, returns the -// default_value. -PROTOBUF_EXPORT double GetDoubleOptionOrDefault( - const RepeatedPtrField& options, - absl::string_view option_name, double default_value); - -// Returns string option value. If the option isn't found, returns the -// default_value. -PROTOBUF_EXPORT std::string GetStringOptionOrDefault( - const RepeatedPtrField& options, - absl::string_view option_name, absl::string_view default_value); - -// Returns a boolean value contained in Any type. -// TODO(skarvaje): Make these utilities dealing with Any types more generic, -// add more error checking and move to a more public/shareable location so -// others can use. -PROTOBUF_EXPORT bool GetBoolFromAny(const google::protobuf::Any& any); - -// Returns int64 value contained in Any type. -PROTOBUF_EXPORT int64_t GetInt64FromAny(const google::protobuf::Any& any); - -// Returns double value contained in Any type. -PROTOBUF_EXPORT double GetDoubleFromAny(const google::protobuf::Any& any); - -// Returns string value contained in Any type. -PROTOBUF_EXPORT std::string GetStringFromAny(const google::protobuf::Any& any); - -// Returns the type string without the url prefix. e.g.: If the passed type is -// 'type.googleapis.com/tech.type.Bool', the returned value is 'tech.type.Bool'. -PROTOBUF_EXPORT absl::string_view GetTypeWithoutUrl( - absl::string_view type_url); - -// Returns the simple_type with the base type url (kTypeServiceBaseUrl) -// prefixed. -// -// E.g: -// GetFullTypeWithUrl("google.protobuf.Timestamp") returns the string -// "type.googleapis.com/google.protobuf.Timestamp". -PROTOBUF_EXPORT std::string GetFullTypeWithUrl( - absl::string_view simple_type); - -// Finds and returns option identified by name and option_name within the -// provided map. Returns nullptr if none found. -const google::protobuf::Option* FindOptionOrNull( - const RepeatedPtrField& options, - absl::string_view option_name); - -// Finds and returns the field identified by field_name in the passed tech Type -// object. Returns nullptr if none found. -const google::protobuf::Field* FindFieldInTypeOrNull( - const google::protobuf::Type* type, absl::string_view field_name); - -// Similar to FindFieldInTypeOrNull, but this looks up fields with given -// json_name. -const google::protobuf::Field* FindJsonFieldInTypeOrNull( - const google::protobuf::Type* type, absl::string_view json_name); - -// Similar to FindFieldInTypeOrNull, but this looks up fields by number. -const google::protobuf::Field* FindFieldInTypeByNumberOrNull( - const google::protobuf::Type* type, int32_t number); - -// Finds and returns the EnumValue identified by enum_name in the passed tech -// Enum object. Returns nullptr if none found. -const google::protobuf::EnumValue* FindEnumValueByNameOrNull( - const google::protobuf::Enum* enum_type, absl::string_view enum_name); - -// Finds and returns the EnumValue identified by value in the passed tech -// Enum object. Returns nullptr if none found. -const google::protobuf::EnumValue* FindEnumValueByNumberOrNull( - const google::protobuf::Enum* enum_type, int32_t value); - -// Finds and returns the EnumValue identified by enum_name without underscore in -// the passed tech Enum object. Returns nullptr if none found. -// For Ex. if enum_name is ACTIONANDADVENTURE it can get accepted if -// EnumValue's name is action_and_adventure or ACTION_AND_ADVENTURE. -const google::protobuf::EnumValue* FindEnumValueByNameWithoutUnderscoreOrNull( - const google::protobuf::Enum* enum_type, absl::string_view enum_name); - -// Converts input to camel-case and returns it. -PROTOBUF_EXPORT std::string ToCamelCase(const absl::string_view input); - -// Converts enum name string to camel-case and returns it. -std::string EnumValueNameToLowerCamelCase(const absl::string_view input); - -// Converts input to snake_case and returns it. -PROTOBUF_EXPORT std::string ToSnakeCase(absl::string_view input); - -// Returns true if type_name represents a well-known type. -PROTOBUF_EXPORT bool IsWellKnownType(const std::string& type_name); - -// Returns true if 'bool_string' represents a valid boolean value. Only "true", -// "false", "0" and "1" are allowed. -PROTOBUF_EXPORT bool IsValidBoolString(absl::string_view bool_string); - -// Returns true if "field" is a protobuf map field based on its type. -PROTOBUF_EXPORT bool IsMap(const google::protobuf::Field& field, - const google::protobuf::Type& type); - -// Returns true if the given type has special MessageSet wire format. -bool IsMessageSetWireFormat(const google::protobuf::Type& type); - -// Infinity/NaN-aware conversion to string. -PROTOBUF_EXPORT std::string DoubleAsString(double value); -PROTOBUF_EXPORT std::string FloatAsString(float value); - -// Convert from int32, int64, uint32, uint64, double or float to string. -template -std::string ValueAsString(T value) { - return absl::StrCat(value); -} - -template <> -inline std::string ValueAsString(float value) { - return FloatAsString(value); -} - -template <> -inline std::string ValueAsString(double value) { - return DoubleAsString(value); -} - -// Converts a string to float. Unlike safe_strtof, conversion will fail if the -// value fits into double but not float (e.g., DBL_MAX). -PROTOBUF_EXPORT bool SafeStrToFloat(absl::string_view str, float* value); - -} // namespace converter -} // namespace util -} // namespace protobuf -} // namespace google - -#include "google/protobuf/port_undef.inc" - -#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_UTILITY_H__ diff --git a/src/google/protobuf/util/json_format.proto b/src/google/protobuf/util/json_format.proto index 7b7100d788..6199f09e83 100644 --- a/src/google/protobuf/util/json_format.proto +++ b/src/google/protobuf/util/json_format.proto @@ -38,6 +38,10 @@ syntax = "proto2"; package protobuf_unittest; +import "google/protobuf/any.proto"; +import "google/protobuf/struct.proto"; + + message TestFlagsAndStrings { required int32 A = 1; repeated group RepeatedGroup = 2 { diff --git a/src/google/protobuf/util/json_format_proto3.proto b/src/google/protobuf/util/json_format_proto3.proto index 4df5eb9d3e..62c2316a9e 100644 --- a/src/google/protobuf/util/json_format_proto3.proto +++ b/src/google/protobuf/util/json_format_proto3.proto @@ -206,3 +206,107 @@ message TestEnumValue { EnumType enum_value2 = 2; EnumType enum_value3 = 3; } + +message MapsTestCases { + EmptyMap empty_map = 1; + StringtoInt string_to_int = 2; + IntToString int_to_string = 3; + Mixed1 mixed1 = 4; + Mixed2 mixed2 = 5; + MapOfObjects map_of_objects = 6; + + // Empty key tests + StringtoInt empty_key_string_to_int1 = 7; + StringtoInt empty_key_string_to_int2 = 8; + StringtoInt empty_key_string_to_int3 = 9; + BoolToString empty_key_bool_to_string = 10; + IntToString empty_key_int_to_string = 11; + Mixed1 empty_key_mixed = 12; + MapOfObjects empty_key_map_objects = 13; +} + +message EmptyMap { + map map = 1; +} + +message StringtoInt { + map map = 1; +} + +message IntToString { + map map = 1; +} + +message BoolToString { + map map = 1; +} + +message Mixed1 { + string msg = 1; + map map = 2; +} + +message Mixed2 { + enum E { + E0 = 0; + E1 = 1; + E2 = 2; + E3 = 3; + } + map map = 1; + E ee = 2; +} + +message MapOfObjects { + message M { + string inner_text = 1; + } + map map = 1; +} + +message MapIn { + string other = 1; + repeated string things = 2; + map map_input = 3; + map map_any = 4; +} + +message MapOut { + map map1 = 1; + map map2 = 2; + map map3 = 3; + map map4 = 5; + string bar = 4; +} + +// A message with exactly the same wire representation as MapOut, but using +// repeated message fields instead of map fields. We use this message to test +// the wire-format compatibility of the JSON transcoder (e.g., whether it +// handles missing keys correctly). +message MapOutWireFormat { + message Map1Entry { + string key = 1; + MapM value = 2; + } + repeated Map1Entry map1 = 1; + message Map2Entry { + string key = 1; + MapOut value = 2; + } + repeated Map2Entry map2 = 2; + message Map3Entry { + int32 key = 1; + string value = 2; + } + repeated Map3Entry map3 = 3; + message Map4Entry { + bool key = 1; + string value = 2; + } + repeated Map4Entry map4 = 5; + string bar = 4; +} + +message MapM { + string foo = 1; +} diff --git a/src/google/protobuf/util/json_util.cc b/src/google/protobuf/util/json_util.cc deleted file mode 100644 index 2942eeb516..0000000000 --- a/src/google/protobuf/util/json_util.cc +++ /dev/null @@ -1,264 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google/protobuf/util/json_util.h" - -#include "absl/base/call_once.h" -#include "absl/status/status.h" -#include "absl/strings/ascii.h" -#include "google/protobuf/stubs/bytestream.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/string_view.h" -#include "google/protobuf/io/coded_stream.h" -#include "google/protobuf/io/zero_copy_sink.h" -#include "google/protobuf/io/zero_copy_stream.h" -#include "google/protobuf/util/internal/default_value_objectwriter.h" -#include "google/protobuf/util/internal/error_listener.h" -#include "google/protobuf/util/internal/json_objectwriter.h" -#include "google/protobuf/util/internal/json_stream_parser.h" -#include "google/protobuf/util/internal/protostream_objectsource.h" -#include "google/protobuf/util/internal/protostream_objectwriter.h" -#include "google/protobuf/util/type_resolver.h" -#include "google/protobuf/util/type_resolver_util.h" -#include "google/protobuf/stubs/status_macros.h" - - -// clang-format off -#include "google/protobuf/port_def.inc" -// clang-format on - - -namespace google { -namespace protobuf { -namespace util { -using ::google::protobuf::io::zc_sink_internal::ZeroCopyStreamByteSink; - -absl::Status BinaryToJsonStream(TypeResolver* resolver, - const std::string& type_url, - io::ZeroCopyInputStream* binary_input, - io::ZeroCopyOutputStream* json_output, - const JsonPrintOptions& options) { - - io::CodedInputStream in_stream(binary_input); - google::protobuf::Type type; - RETURN_IF_ERROR(resolver->ResolveMessageType(type_url, &type)); - converter::ProtoStreamObjectSource::RenderOptions render_options; - render_options.use_ints_for_enums = options.always_print_enums_as_ints; - render_options.preserve_proto_field_names = - options.preserve_proto_field_names; - converter::ProtoStreamObjectSource proto_source(&in_stream, resolver, type, - render_options); - io::CodedOutputStream out_stream(json_output); - converter::JsonObjectWriter json_writer(options.add_whitespace ? " " : "", - &out_stream); - if (options.always_print_primitive_fields) { - converter::DefaultValueObjectWriter default_value_writer(resolver, type, - &json_writer); - default_value_writer.set_preserve_proto_field_names( - options.preserve_proto_field_names); - default_value_writer.set_print_enums_as_ints( - options.always_print_enums_as_ints); - return proto_source.WriteTo(&default_value_writer); - } else { - return proto_source.WriteTo(&json_writer); - } -} - -absl::Status BinaryToJsonString(TypeResolver* resolver, - const std::string& type_url, - const std::string& binary_input, - std::string* json_output, - const JsonPrintOptions& options) { - io::ArrayInputStream input_stream(binary_input.data(), binary_input.size()); - io::StringOutputStream output_stream(json_output); - return BinaryToJsonStream(resolver, type_url, &input_stream, &output_stream, - options); -} - -namespace { -class StatusErrorListener : public converter::ErrorListener { - public: - StatusErrorListener() {} - StatusErrorListener(const StatusErrorListener&) = delete; - StatusErrorListener& operator=(const StatusErrorListener&) = delete; - ~StatusErrorListener() override {} - - absl::Status GetStatus() { return status_; } - - void InvalidName(const converter::LocationTrackerInterface& loc, - absl::string_view unknown_name, - absl::string_view message) override { - std::string loc_string = GetLocString(loc); - if (!loc_string.empty()) { - loc_string.append(" "); - } - status_ = absl::InvalidArgumentError( - absl::StrCat(loc_string, unknown_name, ": ", message)); - } - - void InvalidValue(const converter::LocationTrackerInterface& loc, - absl::string_view type_name, - absl::string_view value) override { - status_ = absl::InvalidArgumentError( - absl::StrCat(GetLocString(loc), ": invalid value ", std::string(value), - " for type ", std::string(type_name))); - } - - void MissingField(const converter::LocationTrackerInterface& loc, - absl::string_view missing_name) override { - status_ = absl::InvalidArgumentError(absl::StrCat( - GetLocString(loc), ": missing field ", std::string(missing_name))); - } - - private: - absl::Status status_; - - std::string GetLocString(const converter::LocationTrackerInterface& loc) { - std::string loc_string = loc.ToString(); - absl::StripAsciiWhitespace(&loc_string); - if (!loc_string.empty()) { - loc_string = absl::StrCat("(", loc_string, ")"); - } - return loc_string; - } -}; -} // namespace - -absl::Status JsonToBinaryStream(TypeResolver* resolver, - const std::string& type_url, - io::ZeroCopyInputStream* json_input, - io::ZeroCopyOutputStream* binary_output, - const JsonParseOptions& options) { - - google::protobuf::Type type; - RETURN_IF_ERROR(resolver->ResolveMessageType(type_url, &type)); - ZeroCopyStreamByteSink sink(binary_output); - StatusErrorListener listener; - converter::ProtoStreamObjectWriter::Options proto_writer_options; - proto_writer_options.ignore_unknown_fields = options.ignore_unknown_fields; - proto_writer_options.ignore_unknown_enum_values = - options.ignore_unknown_fields; - proto_writer_options.case_insensitive_enum_parsing = - options.case_insensitive_enum_parsing; - converter::ProtoStreamObjectWriter proto_writer( - resolver, type, &sink, &listener, proto_writer_options); - proto_writer.set_use_strict_base64_decoding(false); - - converter::JsonStreamParser parser(&proto_writer); - const void* buffer; - int length; - while (json_input->Next(&buffer, &length)) { - if (length == 0) continue; - RETURN_IF_ERROR(parser.Parse( - absl::string_view(static_cast(buffer), length))); - } - RETURN_IF_ERROR(parser.FinishParse()); - - return listener.GetStatus(); -} - -absl::Status JsonToBinaryString(TypeResolver* resolver, - const std::string& type_url, - absl::string_view json_input, - std::string* binary_output, - const JsonParseOptions& options) { - io::ArrayInputStream input_stream(json_input.data(), json_input.size()); - io::StringOutputStream output_stream(binary_output); - return JsonToBinaryStream(resolver, type_url, &input_stream, &output_stream, - options); -} - -namespace { -const char* kTypeUrlPrefix = "type.googleapis.com"; -TypeResolver* generated_type_resolver_ = nullptr; -absl::once_flag generated_type_resolver_init_; - -std::string GetTypeUrl(const Message& message) { - return std::string(kTypeUrlPrefix) + "/" + - message.GetDescriptor()->full_name(); -} - -void DeleteGeneratedTypeResolver() { // NOLINT - delete generated_type_resolver_; -} - -void InitGeneratedTypeResolver() { - generated_type_resolver_ = NewTypeResolverForDescriptorPool( - kTypeUrlPrefix, DescriptorPool::generated_pool()); - ::google::protobuf::internal::OnShutdown(&DeleteGeneratedTypeResolver); -} - -TypeResolver* GetGeneratedTypeResolver() { - absl::call_once(generated_type_resolver_init_, InitGeneratedTypeResolver); - return generated_type_resolver_; -} -} // namespace - -absl::Status MessageToJsonString(const Message& message, std::string* output, - const JsonOptions& options) { - - const DescriptorPool* pool = message.GetDescriptor()->file()->pool(); - TypeResolver* resolver = - pool == DescriptorPool::generated_pool() - ? GetGeneratedTypeResolver() - : NewTypeResolverForDescriptorPool(kTypeUrlPrefix, pool); - absl::Status result = - BinaryToJsonString(resolver, GetTypeUrl(message), - message.SerializeAsString(), output, options); - if (pool != DescriptorPool::generated_pool()) { - delete resolver; - } - return result; -} - -absl::Status JsonStringToMessage(absl::string_view input, Message* message, - const JsonParseOptions& options) { - - const DescriptorPool* pool = message->GetDescriptor()->file()->pool(); - TypeResolver* resolver = - pool == DescriptorPool::generated_pool() - ? GetGeneratedTypeResolver() - : NewTypeResolverForDescriptorPool(kTypeUrlPrefix, pool); - std::string binary; - absl::Status result = JsonToBinaryString(resolver, GetTypeUrl(*message), - input, &binary, options); - if (result.ok() && !message->ParseFromString(binary)) { - result = absl::InvalidArgumentError( - "JSON transcoder produced invalid protobuf output."); - } - if (pool != DescriptorPool::generated_pool()) { - delete resolver; - } - return result; -} - -} // namespace util -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/util/json_util.h b/src/google/protobuf/util/json_util.h index fe7444197a..2f4f2cb220 100644 --- a/src/google/protobuf/util/json_util.h +++ b/src/google/protobuf/util/json_util.h @@ -33,165 +33,30 @@ #ifndef GOOGLE_PROTOBUF_UTIL_JSON_UTIL_H__ #define GOOGLE_PROTOBUF_UTIL_JSON_UTIL_H__ +#include "absl/base/attributes.h" -#include "absl/status/status.h" -#include "google/protobuf/stubs/bytestream.h" -#include "absl/strings/string_view.h" -#include "google/protobuf/message.h" -#include "google/protobuf/util/type_resolver.h" -// Must be included last. -#include "google/protobuf/port_def.inc" +#include "google/protobuf/json/json.h" namespace google { namespace protobuf { -namespace io { -class ZeroCopyInputStream; -class ZeroCopyOutputStream; -} // namespace io namespace util { +using JsonParseOptions = ::google::protobuf::json::ParseOptions; +using JsonPrintOptions = ::google::protobuf::json::PrintOptions; -struct JsonParseOptions { - // Whether to ignore unknown JSON fields during parsing - bool ignore_unknown_fields; +using JsonOptions ABSL_DEPRECATED("use JsonPrintOptions instead") = + JsonPrintOptions; - // If true, when a lowercase enum value fails to parse, try convert it to - // UPPER_CASE and see if it matches a valid enum. - // WARNING: This option exists only to preserve legacy behavior. Avoid using - // this option. If your enum needs to support different casing, consider using - // allow_alias instead. - bool case_insensitive_enum_parsing; +using ::google::protobuf::json::BinaryToJsonStream; +using ::google::protobuf::json::BinaryToJsonString; - JsonParseOptions() - : ignore_unknown_fields(false), case_insensitive_enum_parsing(false) {} -}; +using ::google::protobuf::json::JsonStringToMessage; +using ::google::protobuf::json::JsonToBinaryStream; -struct JsonPrintOptions { - // Whether to add spaces, line breaks and indentation to make the JSON output - // easy to read. - bool add_whitespace; - // Whether to always print primitive fields. By default proto3 primitive - // fields with default values will be omitted in JSON output. For example, an - // int32 field set to 0 will be omitted. Set this flag to true will override - // the default behavior and print primitive fields regardless of their values. - bool always_print_primitive_fields; - // Whether to always print enums as ints. By default they are rendered as - // strings. - bool always_print_enums_as_ints; - // Whether to preserve proto field names - bool preserve_proto_field_names; - - JsonPrintOptions() - : add_whitespace(false), - always_print_primitive_fields(false), - always_print_enums_as_ints(false), - preserve_proto_field_names(false) {} -}; - -// DEPRECATED. Use JsonPrintOptions instead. -typedef JsonPrintOptions JsonOptions; - -// Converts from protobuf message to JSON and appends it to |output|. This is a -// simple wrapper of BinaryToJsonString(). It will use the DescriptorPool of the -// passed-in message to resolve Any types. -// -// Please note that non-OK statuses are not a stable output of this API and -// subject to change without notice. -PROTOBUF_EXPORT absl::Status MessageToJsonString(const Message& message, - std::string* output, - const JsonOptions& options); - -inline absl::Status MessageToJsonString(const Message& message, - std::string* output) { - return MessageToJsonString(message, output, JsonOptions()); -} - -// Converts from JSON to protobuf message. This is a simple wrapper of -// JsonStringToBinary(). It will use the DescriptorPool of the passed-in -// message to resolve Any types. -// -// Please note that non-OK statuses are not a stable output of this API and -// subject to change without notice. -PROTOBUF_EXPORT absl::Status JsonStringToMessage( - absl::string_view input, Message* message, const JsonParseOptions& options); - -inline absl::Status JsonStringToMessage(absl::string_view input, - Message* message) { - return JsonStringToMessage(input, message, JsonParseOptions()); -} - -// Converts protobuf binary data to JSON. -// The conversion will fail if: -// 1. TypeResolver fails to resolve a type. -// 2. input is not valid protobuf wire format, or conflicts with the type -// information returned by TypeResolver. -// Note that unknown fields will be discarded silently. -// -// Please note that non-OK statuses are not a stable output of this API and -// subject to change without notice. -PROTOBUF_EXPORT absl::Status BinaryToJsonStream( - TypeResolver* resolver, const std::string& type_url, - io::ZeroCopyInputStream* binary_input, - io::ZeroCopyOutputStream* json_output, const JsonPrintOptions& options); - -inline absl::Status BinaryToJsonStream(TypeResolver* resolver, - const std::string& type_url, - io::ZeroCopyInputStream* binary_input, - io::ZeroCopyOutputStream* json_output) { - return BinaryToJsonStream(resolver, type_url, binary_input, json_output, - JsonPrintOptions()); -} - -PROTOBUF_EXPORT absl::Status BinaryToJsonString( - TypeResolver* resolver, const std::string& type_url, - const std::string& binary_input, std::string* json_output, - const JsonPrintOptions& options); - -inline absl::Status BinaryToJsonString(TypeResolver* resolver, - const std::string& type_url, - const std::string& binary_input, - std::string* json_output) { - return BinaryToJsonString(resolver, type_url, binary_input, json_output, - JsonPrintOptions()); -} - -// Converts JSON data to protobuf binary format. -// The conversion will fail if: -// 1. TypeResolver fails to resolve a type. -// 2. input is not valid JSON format, or conflicts with the type -// information returned by TypeResolver. -// -// Please note that non-OK statuses are not a stable output of this API and -// subject to change without notice. -PROTOBUF_EXPORT absl::Status JsonToBinaryStream( - TypeResolver* resolver, const std::string& type_url, - io::ZeroCopyInputStream* json_input, - io::ZeroCopyOutputStream* binary_output, const JsonParseOptions& options); - -inline absl::Status JsonToBinaryStream( - TypeResolver* resolver, const std::string& type_url, - io::ZeroCopyInputStream* json_input, - io::ZeroCopyOutputStream* binary_output) { - return JsonToBinaryStream(resolver, type_url, json_input, binary_output, - JsonParseOptions()); -} - -PROTOBUF_EXPORT absl::Status JsonToBinaryString( - TypeResolver* resolver, const std::string& type_url, - absl::string_view json_input, std::string* binary_output, - const JsonParseOptions& options); - -inline absl::Status JsonToBinaryString(TypeResolver* resolver, - const std::string& type_url, - absl::string_view json_input, - std::string* binary_output) { - return JsonToBinaryString(resolver, type_url, json_input, binary_output, - JsonParseOptions()); -} +using ::google::protobuf::json::JsonToBinaryString; +using ::google::protobuf::json::MessageToJsonString; } // namespace util } // namespace protobuf } // namespace google -#include "google/protobuf/port_undef.inc" - #endif // GOOGLE_PROTOBUF_UTIL_JSON_UTIL_H__ diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc index 00a0e9d7e6..3c990c939f 100644 --- a/src/google/protobuf/util/message_differencer.cc +++ b/src/google/protobuf/util/message_differencer.cc @@ -54,7 +54,6 @@ #include "google/protobuf/map_field.h" #include "google/protobuf/message.h" #include "google/protobuf/text_format.h" -#include "google/protobuf/stubs/strutil.h" #include "absl/container/fixed_array.h" #include "absl/strings/escaping.h" #include "absl/strings/match.h" @@ -161,9 +160,11 @@ class MessageDifferencer::MultipleFieldsMapKeyComparator MultipleFieldsMapKeyComparator& operator=( const MultipleFieldsMapKeyComparator&) = delete; bool IsMatch(const Message& message1, const Message& message2, + int unpacked_any, const std::vector& parent_fields) const override { for (const auto& path : key_field_paths_) { - if (!IsMatchInternal(message1, message2, parent_fields, path, 0)) { + if (!IsMatchInternal(message1, message2, unpacked_any, parent_fields, + path, 0)) { return false; } } @@ -172,7 +173,7 @@ class MessageDifferencer::MultipleFieldsMapKeyComparator private: bool IsMatchInternal( - const Message& message1, const Message& message2, + const Message& message1, const Message& message2, int unpacked_any, const std::vector& parent_fields, const std::vector& key_field_path, int path_index) const { @@ -180,14 +181,15 @@ class MessageDifferencer::MultipleFieldsMapKeyComparator std::vector current_parent_fields(parent_fields); if (path_index == static_cast(key_field_path.size() - 1)) { if (field->is_map()) { - return message_differencer_->CompareMapField(message1, message2, field, - ¤t_parent_fields); + return message_differencer_->CompareMapField( + message1, message2, unpacked_any, field, ¤t_parent_fields); } else if (field->is_repeated()) { return message_differencer_->CompareRepeatedField( - message1, message2, field, ¤t_parent_fields); + message1, message2, unpacked_any, field, ¤t_parent_fields); } else { return message_differencer_->CompareFieldValueUsingParentFields( - message1, message2, field, -1, -1, ¤t_parent_fields); + message1, message2, unpacked_any, field, -1, -1, + ¤t_parent_fields); } } else { const Reflection* reflection1 = message1.GetReflection(); @@ -201,12 +203,15 @@ class MessageDifferencer::MultipleFieldsMapKeyComparator return false; } SpecificField specific_field; + specific_field.message1 = &message1; + specific_field.message2 = &message2; + specific_field.unpacked_any = unpacked_any; specific_field.field = field; current_parent_fields.push_back(specific_field); return IsMatchInternal(reflection1->GetMessage(message1, field), reflection2->GetMessage(message2, field), - current_parent_fields, key_field_path, - path_index + 1); + false /*key is never Any*/, current_parent_fields, + key_field_path, path_index + 1); } } MessageDifferencer* message_differencer_; @@ -261,7 +266,7 @@ MessageDifferencer::MapEntryKeyComparator::MapEntryKeyComparator( : message_differencer_(message_differencer) {} bool MessageDifferencer::MapEntryKeyComparator::IsMatch( - const Message& message1, const Message& message2, + const Message& message1, const Message& message2, int unpacked_any, const std::vector& parent_fields) const { // Map entry has its key in the field with tag 1. See the comment for // map_entry in MessageOptions. @@ -275,11 +280,11 @@ bool MessageDifferencer::MapEntryKeyComparator::IsMatch( std::vector current_parent_fields(parent_fields); if (treat_as_set) { - return message_differencer_->Compare(message1, message2, + return message_differencer_->Compare(message1, message2, unpacked_any, ¤t_parent_fields); } return message_differencer_->CompareFieldValueUsingParentFields( - message1, message2, key, -1, -1, ¤t_parent_fields); + message1, message2, unpacked_any, key, -1, -1, ¤t_parent_fields); } bool MessageDifferencer::Equals(const Message& message1, @@ -333,9 +338,6 @@ MessageDifferencer::~MessageDifferencer() { for (MapKeyComparator* comparator : owned_key_comparators_) { delete comparator; } - for (IgnoreCriteria* criteria : ignore_criteria_) { - delete criteria; - } } void MessageDifferencer::set_field_comparator(FieldComparator* comparator) { @@ -497,8 +499,9 @@ void MessageDifferencer::TreatAsMapUsingKeyComparator( map_field_key_comparator_[field] = key_comparator; } -void MessageDifferencer::AddIgnoreCriteria(IgnoreCriteria* ignore_criteria) { - ignore_criteria_.push_back(ignore_criteria); +void MessageDifferencer::AddIgnoreCriteria( + std::unique_ptr ignore_criteria) { + ignore_criteria_.push_back(std::move(ignore_criteria)); } void MessageDifferencer::IgnoreField(const FieldDescriptor* field) { @@ -554,10 +557,10 @@ bool MessageDifferencer::Compare(const Message& message1, StreamReporter reporter(&output_stream); reporter.SetMessages(message1, message2); reporter_ = &reporter; - result = Compare(message1, message2, &parent_fields); + result = Compare(message1, message2, false, &parent_fields); reporter_ = NULL; } else { - result = Compare(message1, message2, &parent_fields); + result = Compare(message1, message2, false, &parent_fields); } return result; } @@ -597,18 +600,20 @@ bool MessageDifferencer::CompareWithFields( StreamReporter reporter(&output_stream); reporter_ = &reporter; result = CompareRequestedFieldsUsingSettings( - message1, message2, message1_fields, message2_fields, &parent_fields); + message1, message2, false, message1_fields, message2_fields, + &parent_fields); reporter_ = NULL; } else { result = CompareRequestedFieldsUsingSettings( - message1, message2, message1_fields, message2_fields, &parent_fields); + message1, message2, false, message1_fields, message2_fields, + &parent_fields); } return result; } bool MessageDifferencer::Compare(const Message& message1, - const Message& message2, + const Message& message2, int unpacked_any, std::vector* parent_fields) { const Descriptor* descriptor1 = message1.GetDescriptor(); const Descriptor* descriptor2 = message2.GetDescriptor(); @@ -629,7 +634,7 @@ bool MessageDifferencer::Compare(const Message& message1, if (data1->GetDescriptor() != data2->GetDescriptor()) { return false; } - return Compare(*data1, *data2, parent_fields); + return Compare(*data1, *data2, unpacked_any + 1, parent_fields); } } const Reflection* reflection1 = message1.GetReflection(); @@ -654,7 +659,7 @@ bool MessageDifferencer::Compare(const Message& message1, FieldDescriptorArray message1_fields = RetrieveFields(message1, true); FieldDescriptorArray message2_fields = RetrieveFields(message2, false); - return CompareRequestedFieldsUsingSettings(message1, message2, + return CompareRequestedFieldsUsingSettings(message1, message2, unpacked_any, message1_fields, message2_fields, parent_fields) && unknown_compare_result; @@ -692,7 +697,7 @@ FieldDescriptorArray MessageDifferencer::RetrieveFields(const Message& message, } bool MessageDifferencer::CompareRequestedFieldsUsingSettings( - const Message& message1, const Message& message2, + const Message& message1, const Message& message2, int unpacked_any, const FieldDescriptorArray& message1_fields, const FieldDescriptorArray& message2_fields, std::vector* parent_fields) { @@ -703,20 +708,23 @@ bool MessageDifferencer::CompareRequestedFieldsUsingSettings( // rather than the addition or deletion of fields). FieldDescriptorArray fields_union = CombineFields(message1_fields, FULL, message2_fields, FULL); - return CompareWithFieldsInternal(message1, message2, fields_union, - fields_union, parent_fields); + return CompareWithFieldsInternal(message1, message2, unpacked_any, + fields_union, fields_union, + parent_fields); } else { // Simple equality comparison, use the unaltered field lists. - return CompareWithFieldsInternal(message1, message2, message1_fields, - message2_fields, parent_fields); + return CompareWithFieldsInternal(message1, message2, unpacked_any, + message1_fields, message2_fields, + parent_fields); } } else { if (message_field_comparison_ == EQUIVALENT) { // We use the list of fields for message1 for both messages when // comparing. This way, extra fields in message2 are ignored, // and missing fields in message2 use their default value. - return CompareWithFieldsInternal(message1, message2, message1_fields, - message1_fields, parent_fields); + return CompareWithFieldsInternal(message1, message2, unpacked_any, + message1_fields, message1_fields, + parent_fields); } else { // We need to consider the full list of fields for message1 // but only the intersection for message2. This way, any fields @@ -724,8 +732,9 @@ bool MessageDifferencer::CompareRequestedFieldsUsingSettings( // present in message1 will be marked as a difference. FieldDescriptorArray fields_intersection = CombineFields(message1_fields, PARTIAL, message2_fields, PARTIAL); - return CompareWithFieldsInternal(message1, message2, message1_fields, - fields_intersection, parent_fields); + return CompareWithFieldsInternal(message1, message2, unpacked_any, + message1_fields, fields_intersection, + parent_fields); } } } @@ -768,7 +777,7 @@ FieldDescriptorArray MessageDifferencer::CombineFields( } bool MessageDifferencer::CompareWithFieldsInternal( - const Message& message1, const Message& message2, + const Message& message1, const Message& message2, int unpacked_any, const FieldDescriptorArray& message1_fields, const FieldDescriptorArray& message2_fields, std::vector* parent_fields) { @@ -796,6 +805,9 @@ bool MessageDifferencer::CompareWithFieldsInternal( // the next field in message1_fields. if (reporter_ != NULL) { SpecificField specific_field; + specific_field.message1 = &message1; + specific_field.message2 = &message2; + specific_field.unpacked_any = unpacked_any; specific_field.field = field1; parent_fields->push_back(specific_field); if (report_ignores_) { @@ -815,6 +827,9 @@ bool MessageDifferencer::CompareWithFieldsInternal( for (int i = 0; i < count; ++i) { SpecificField specific_field; + specific_field.message1 = &message1; + specific_field.message2 = &message2; + specific_field.unpacked_any = unpacked_any; specific_field.field = field1; if (field1->is_repeated()) { AddSpecificIndex(&specific_field, message1, field1, i); @@ -841,6 +856,9 @@ bool MessageDifferencer::CompareWithFieldsInternal( // the next field in message2_fields. if (reporter_ != NULL) { SpecificField specific_field; + specific_field.message1 = &message1; + specific_field.message2 = &message2; + specific_field.unpacked_any = unpacked_any; specific_field.field = field2; parent_fields->push_back(specific_field); if (report_ignores_) { @@ -859,6 +877,9 @@ bool MessageDifferencer::CompareWithFieldsInternal( for (int i = 0; i < count; ++i) { SpecificField specific_field; + specific_field.message1 = &message1, + specific_field.message2 = &message2; + specific_field.unpacked_any = unpacked_any; specific_field.field = field2; if (field2->is_repeated()) { specific_field.index = i; @@ -888,6 +909,9 @@ bool MessageDifferencer::CompareWithFieldsInternal( // Ignore this field. Report and move on. if (reporter_ != NULL) { SpecificField specific_field; + specific_field.message1 = &message1; + specific_field.message2 = &message2; + specific_field.unpacked_any = unpacked_any; specific_field.field = field1; parent_fields->push_back(specific_field); if (report_ignores_) { @@ -904,17 +928,20 @@ bool MessageDifferencer::CompareWithFieldsInternal( bool fieldDifferent = false; assert(field1 != NULL); if (field1->is_map()) { - fieldDifferent = - !CompareMapField(message1, message2, field1, parent_fields); + fieldDifferent = !CompareMapField(message1, message2, unpacked_any, + field1, parent_fields); } else if (field1->is_repeated()) { - fieldDifferent = - !CompareRepeatedField(message1, message2, field1, parent_fields); + fieldDifferent = !CompareRepeatedField(message1, message2, unpacked_any, + field1, parent_fields); } else { fieldDifferent = !CompareFieldValueUsingParentFields( - message1, message2, field1, -1, -1, parent_fields); + message1, message2, unpacked_any, field1, -1, -1, parent_fields); if (reporter_ != nullptr) { SpecificField specific_field; + specific_field.message1 = &message1; + specific_field.message2 = &message2; + specific_field.unpacked_any = unpacked_any; specific_field.field = field1; parent_fields->push_back(specific_field); if (fieldDifferent) { @@ -941,13 +968,14 @@ bool MessageDifferencer::CompareWithFieldsInternal( bool MessageDifferencer::IsMatch( const FieldDescriptor* repeated_field, const MapKeyComparator* key_comparator, const Message* message1, - const Message* message2, const std::vector& parent_fields, - Reporter* reporter, int index1, int index2) { + const Message* message2, int unpacked_any, + const std::vector& parent_fields, Reporter* reporter, + int index1, int index2) { std::vector current_parent_fields(parent_fields); if (repeated_field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { - return CompareFieldValueUsingParentFields(*message1, *message2, - repeated_field, index1, index2, - ¤t_parent_fields); + return CompareFieldValueUsingParentFields( + *message1, *message2, unpacked_any, repeated_field, index1, index2, + ¤t_parent_fields); } // Back up the Reporter and output_string_. They will be reset in the // following code. @@ -958,9 +986,9 @@ bool MessageDifferencer::IsMatch( bool match; if (key_comparator == NULL) { - match = CompareFieldValueUsingParentFields(*message1, *message2, - repeated_field, index1, index2, - ¤t_parent_fields); + match = CompareFieldValueUsingParentFields( + *message1, *message2, unpacked_any, repeated_field, index1, index2, + ¤t_parent_fields); } else { const Reflection* reflection1 = message1->GetReflection(); const Reflection* reflection2 = message2->GetReflection(); @@ -969,6 +997,9 @@ bool MessageDifferencer::IsMatch( const Message& m2 = reflection2->GetRepeatedMessage(*message2, repeated_field, index2); SpecificField specific_field; + specific_field.message1 = message1; + specific_field.message2 = message2; + specific_field.unpacked_any = unpacked_any; specific_field.field = repeated_field; if (repeated_field->is_map()) { specific_field.map_entry1 = &m1; @@ -977,7 +1008,7 @@ bool MessageDifferencer::IsMatch( specific_field.index = index1; specific_field.new_index = index2; current_parent_fields.push_back(specific_field); - match = key_comparator->IsMatch(m1, m2, current_parent_fields); + match = key_comparator->IsMatch(m1, m2, false, current_parent_fields); } reporter_ = backup_reporter; @@ -986,7 +1017,7 @@ bool MessageDifferencer::IsMatch( } bool MessageDifferencer::CompareMapFieldByMapReflection( - const Message& message1, const Message& message2, + const Message& message1, const Message& message2, int unpacked_any, const FieldDescriptor* map_field, std::vector* parent_fields, DefaultFieldComparator* comparator) { GOOGLE_DCHECK_EQ(nullptr, reporter_); @@ -1061,10 +1092,14 @@ bool MessageDifferencer::CompareMapFieldByMapReflection( reflection2->LookupMapValue(message2, map_field, it.GetKey(), &value2); // Append currently compared field to the end of parent_fields. SpecificField specific_value_field; + specific_value_field.message1 = &message1; + specific_value_field.message2 = &message2; + specific_value_field.unpacked_any = unpacked_any; specific_value_field.field = val_des; parent_fields->push_back(specific_value_field); - compare_result = Compare(it.GetValueRef().GetMessageValue(), - value2.GetMessageValue(), parent_fields); + compare_result = + Compare(it.GetValueRef().GetMessageValue(), + value2.GetMessageValue(), false, parent_fields); parent_fields->pop_back(); if (!compare_result) { return false; @@ -1077,7 +1112,7 @@ bool MessageDifferencer::CompareMapFieldByMapReflection( } bool MessageDifferencer::CompareMapField( - const Message& message1, const Message& message2, + const Message& message1, const Message& message2, int unpacked_any, const FieldDescriptor* repeated_field, std::vector* parent_fields) { GOOGLE_DCHECK(repeated_field->is_map()); @@ -1103,29 +1138,34 @@ bool MessageDifferencer::CompareMapField( repeated_field->message_type()->map_value(); std::vector current_parent_fields(*parent_fields); SpecificField specific_field; + specific_field.message1 = &message1; + specific_field.message2 = &message2; + specific_field.unpacked_any = unpacked_any; specific_field.field = repeated_field; current_parent_fields.push_back(specific_field); if (!IsIgnored(message1, message2, key_des, current_parent_fields) && !IsIgnored(message1, message2, val_des, current_parent_fields)) { - return CompareMapFieldByMapReflection(message1, message2, repeated_field, - ¤t_parent_fields, - field_comparator_.default_impl); + return CompareMapFieldByMapReflection( + message1, message2, unpacked_any, repeated_field, + ¤t_parent_fields, field_comparator_.default_impl); } } - return CompareRepeatedRep(message1, message2, repeated_field, parent_fields); + return CompareRepeatedRep(message1, message2, unpacked_any, repeated_field, + parent_fields); } bool MessageDifferencer::CompareRepeatedField( - const Message& message1, const Message& message2, + const Message& message1, const Message& message2, int unpacked_any, const FieldDescriptor* repeated_field, std::vector* parent_fields) { GOOGLE_DCHECK(!repeated_field->is_map()); - return CompareRepeatedRep(message1, message2, repeated_field, parent_fields); + return CompareRepeatedRep(message1, message2, unpacked_any, repeated_field, + parent_fields); } bool MessageDifferencer::CompareRepeatedRep( - const Message& message1, const Message& message2, + const Message& message1, const Message& message2, int unpacked_any, const FieldDescriptor* repeated_field, std::vector* parent_fields) { // the input FieldDescriptor is guaranteed to be repeated field. @@ -1164,9 +1204,9 @@ bool MessageDifferencer::CompareRepeatedRep( // match_list2. if (!simple_list) { // Try to match indices of the repeated fields. Return false if match fails. - if (!MatchRepeatedFieldIndices(message1, message2, repeated_field, - key_comparator, *parent_fields, &match_list1, - &match_list2) && + if (!MatchRepeatedFieldIndices( + message1, message2, unpacked_any, repeated_field, key_comparator, + *parent_fields, &match_list1, &match_list2) && reporter_ == nullptr) { return false; } @@ -1174,6 +1214,9 @@ bool MessageDifferencer::CompareRepeatedRep( bool fieldDifferent = false; SpecificField specific_field; + specific_field.message1 = &message1; + specific_field.message2 = &message2; + specific_field.unpacked_any = unpacked_any; specific_field.field = repeated_field; // At this point, we have already matched pairs of fields (with the reporting @@ -1220,8 +1263,8 @@ bool MessageDifferencer::CompareRepeatedRep( } const bool result = CompareFieldValueUsingParentFields( - message1, message2, repeated_field, i, specific_field.new_index, - parent_fields); + message1, message2, unpacked_any, repeated_field, i, + specific_field.new_index, parent_fields); // If we have found differences, either report them or terminate if // no reporter is present. Note that ReportModified, ReportMoved, and @@ -1276,14 +1319,15 @@ bool MessageDifferencer::CompareRepeatedRep( bool MessageDifferencer::CompareFieldValue(const Message& message1, const Message& message2, + int unpacked_any, const FieldDescriptor* field, int index1, int index2) { - return CompareFieldValueUsingParentFields(message1, message2, field, index1, - index2, NULL); + return CompareFieldValueUsingParentFields(message1, message2, unpacked_any, + field, index1, index2, nullptr); } bool MessageDifferencer::CompareFieldValueUsingParentFields( - const Message& message1, const Message& message2, + const Message& message1, const Message& message2, int unpacked_any, const FieldDescriptor* field, int index1, int index2, std::vector* parent_fields) { FieldContext field_context(parent_fields); @@ -1309,11 +1353,14 @@ bool MessageDifferencer::CompareFieldValueUsingParentFields( if (parent_fields != NULL) { // Append currently compared field to the end of parent_fields. SpecificField specific_field; + specific_field.message1 = &message1; + specific_field.message2 = &message2; + specific_field.unpacked_any = unpacked_any; specific_field.field = field; AddSpecificIndex(&specific_field, message1, field, index1); AddSpecificNewIndex(&specific_field, message2, field, index2); parent_fields->push_back(specific_field); - const bool compare_result = Compare(m1, m2, parent_fields); + const bool compare_result = Compare(m1, m2, false, parent_fields); parent_fields->pop_back(); return compare_result; } else { @@ -1378,7 +1425,7 @@ bool MessageDifferencer::IsIgnored( if (ignored_fields_.find(field) != ignored_fields_.end()) { return true; } - for (IgnoreCriteria* criteria : ignore_criteria_) { + for (const auto& criteria : ignore_criteria_) { if (criteria->IsIgnored(message1, message2, field, parent_fields)) { return true; } @@ -1390,7 +1437,7 @@ bool MessageDifferencer::IsUnknownFieldIgnored( const Message& message1, const Message& message2, const SpecificField& field, const std::vector& parent_fields) { - for (IgnoreCriteria* criteria : ignore_criteria_) { + for (const auto& criteria : ignore_criteria_) { if (criteria->IsUnknownFieldIgnored(message1, message2, field, parent_fields)) { return true; @@ -1593,6 +1640,8 @@ bool MessageDifferencer::CompareUnknownFields( // Build the SpecificField. This is slightly complicated. SpecificField specific_field; + specific_field.message1 = &message1; + specific_field.message2 = &message2; specific_field.unknown_field_number = focus_field->number(); specific_field.unknown_field_type = focus_field->type(); @@ -1796,7 +1845,7 @@ bool MaximumMatcher::FindArgumentPathDFS(int v, std::vector* visited) { } // namespace bool MessageDifferencer::MatchRepeatedFieldIndices( - const Message& message1, const Message& message2, + const Message& message1, const Message& message2, int unpacked_any, const FieldDescriptor* repeated_field, const MapKeyComparator* key_comparator, const std::vector& parent_fields, @@ -1830,7 +1879,7 @@ bool MessageDifferencer::MatchRepeatedFieldIndices( // Here we use the augmenting path algorithm. auto callback = [&](int i1, int i2) { return IsMatch(repeated_field, key_comparator, &message1, &message2, - parent_fields, nullptr, i1, i2); + unpacked_any, parent_fields, nullptr, i1, i2); }; MaximumMatcher matcher(count1, count2, std::move(callback), match_list1, match_list2); @@ -1849,7 +1898,7 @@ bool MessageDifferencer::MatchRepeatedFieldIndices( start_offset = std::min(count1, count2); for (int i = 0; i < count1 && i < count2; i++) { if (IsMatch(repeated_field, key_comparator, &message1, &message2, - parent_fields, nullptr, i, i)) { + unpacked_any, parent_fields, nullptr, i, i)) { match_list1->at(i) = i; match_list2->at(i) = i; } else { @@ -1873,11 +1922,12 @@ bool MessageDifferencer::MatchRepeatedFieldIndices( if (is_treated_as_smart_set) { num_diffs_reporter.Reset(); - match = IsMatch(repeated_field, key_comparator, &message1, &message2, - parent_fields, &num_diffs_reporter, i, j); + match = + IsMatch(repeated_field, key_comparator, &message1, &message2, + unpacked_any, parent_fields, &num_diffs_reporter, i, j); } else { match = IsMatch(repeated_field, key_comparator, &message1, &message2, - parent_fields, nullptr, i, j); + unpacked_any, parent_fields, nullptr, i, j); } if (is_treated_as_smart_set) { @@ -2020,7 +2070,6 @@ void MessageDifferencer::StreamReporter::PrintPath( } } - void MessageDifferencer::StreamReporter::PrintValue( const Message& message, const std::vector& field_path, bool left_side) { diff --git a/src/google/protobuf/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h index 7d1e6acbde..e87219300c 100644 --- a/src/google/protobuf/util/message_differencer.h +++ b/src/google/protobuf/util/message_differencer.h @@ -54,6 +54,7 @@ #include "google/protobuf/descriptor.h" // FieldDescriptor #include "google/protobuf/message.h" // Message #include "google/protobuf/unknown_field_set.h" +#include "google/protobuf/stubs/common.h" #include "absl/container/fixed_array.h" #include "google/protobuf/util/field_comparator.h" @@ -178,6 +179,22 @@ class PROTOBUF_EXPORT MessageDifferencer { // Identifies an individual field in a message instance. Used for field_path, // below. struct SpecificField { + // The messages that contain this field. They are always set. They are valid + // only during a call to Reporter::Report* methods. + // + // If the original messages are of type google.protobuf.Any, these fields + // will store the unpacked payloads, and unpacked_any will become > 0. More + // precisely, unpacked_any defines the nesting level of Any. For example, + // if the original message packs another Any, then unpacked_any=2, assuming + // the differencer unpacked both of them. + // + // When an Any object packes a non-Any proto object whose field includes + // Any, then unpacked_any=1. Thus, in most practical applications, + // unpacked_any will be 0 or 1. + const Message* message1 = nullptr; + const Message* message2 = nullptr; + int unpacked_any = 0; + // For known fields, "field" is filled in and "unknown_field_number" is -1. // For unknown fields, "field" is NULL, "unknown_field_number" is the field // number, and "unknown_field_type" is its type. @@ -248,14 +265,13 @@ class PROTOBUF_EXPORT MessageDifferencer { const std::vector& field_path) {} // Reports that a field has been deleted from Message1. - virtual void ReportDeleted( - const Message& message1, const Message& message2, - const std::vector& field_path) {} + virtual void ReportDeleted(const Message& message1, const Message& message2, + const std::vector& field_path) {} // Reports that the value of a field has been modified. - virtual void ReportModified( - const Message& message1, const Message& message2, - const std::vector& field_path) {} + virtual void ReportModified(const Message& message1, + const Message& message2, + const std::vector& field_path) {} // Reports that a repeated field has been moved to another location. This // only applies when using TreatAsSet or TreatAsMap() -- see below. Also @@ -314,12 +330,32 @@ class PROTOBUF_EXPORT MessageDifferencer { MapKeyComparator& operator=(const MapKeyComparator&) = delete; virtual ~MapKeyComparator(); + // This method is DEPRECATED. It is never called directly by + // MessageDifferencer. New code should implement only the next form of + // IsMatch. + // + // TODO(b/248337479) Remove this method. virtual bool IsMatch( const Message& /* message1 */, const Message& /* message2 */, const std::vector& /* parent_fields */) const { GOOGLE_CHECK(false) << "IsMatch() is not implemented."; return false; } + + // This method should be overridden by every implementation. The arg + // unmapped_any is nonzero the original messages provided by the user are of + // type google.protobuf.Any. + // + // More precisely, unpacked_any defines the nesting level of Any. For + // example, if Any packs another Any then unpacked_any=2, assuming the + // patcher unpacked both. Note that when an Any object packes a non-Any + // proto object whose field includes Any, then unpacked_any=1. Thus, in most + // practical applications, unpacked_any will be 0 or 1. + virtual bool IsMatch(const Message& message1, const Message& message2, + int /* unmapped_any */, + const std::vector& fields) const { + return IsMatch(message1, message2, fields); + } }; // Abstract base class from which all IgnoreCriteria derive. @@ -504,7 +540,10 @@ class PROTOBUF_EXPORT MessageDifferencer { // Add a custom ignore criteria that is evaluated in addition to the // ignored fields added with IgnoreField. // Takes ownership of ignore_criteria. - void AddIgnoreCriteria(IgnoreCriteria* ignore_criteria); + void AddIgnoreCriteria(IgnoreCriteria* ignore_criteria) { + AddIgnoreCriteria(absl::WrapUnique(ignore_criteria)); + } + void AddIgnoreCriteria(std::unique_ptr ignore_criteria); // Indicates that any field with the given descriptor should be // ignored for the purposes of comparing two messages. This applies @@ -734,7 +773,7 @@ class PROTOBUF_EXPORT MessageDifferencer { public: explicit MapEntryKeyComparator(MessageDifferencer* message_differencer); bool IsMatch( - const Message& message1, const Message& message2, + const Message& message1, const Message& message2, int unpacked_any, const std::vector& parent_fields) const override; private: @@ -764,7 +803,7 @@ class PROTOBUF_EXPORT MessageDifferencer { // (i.e. if the current message is an embedded message, the parent_fields // vector will contain the field that has this embedded message). bool Compare(const Message& message1, const Message& message2, - std::vector* parent_fields); + int unpacked_any, std::vector* parent_fields); // Compares all the unknown fields in two messages. bool CompareUnknownFields(const Message& message1, const Message& message2, @@ -775,46 +814,47 @@ class PROTOBUF_EXPORT MessageDifferencer { // lists are modified depending on comparison settings, and then passed to // CompareWithFieldsInternal. bool CompareRequestedFieldsUsingSettings( - const Message& message1, const Message& message2, + const Message& message1, const Message& message2, int unpacked_any, const FieldDescriptorArray& message1_fields, const FieldDescriptorArray& message2_fields, std::vector* parent_fields); // Compares the specified messages with the specified field lists. bool CompareWithFieldsInternal(const Message& message1, - const Message& message2, + const Message& message2, int unpacked_any, const FieldDescriptorArray& message1_fields, const FieldDescriptorArray& message2_fields, std::vector* parent_fields); // Compares the repeated fields, and report the error. bool CompareRepeatedField(const Message& message1, const Message& message2, - const FieldDescriptor* field, + int unpacked_any, const FieldDescriptor* field, std::vector* parent_fields); // Compares map fields, and report the error. bool CompareMapField(const Message& message1, const Message& message2, - const FieldDescriptor* field, + int unpacked_any, const FieldDescriptor* field, std::vector* parent_fields); // Helper for CompareRepeatedField and CompareMapField: compares and reports // differences element-wise. This is the implementation for non-map fields, // and can also compare map fields by using the underlying representation. bool CompareRepeatedRep(const Message& message1, const Message& message2, - const FieldDescriptor* field, + int unpacked_any, const FieldDescriptor* field, std::vector* parent_fields); // Helper for CompareMapField: compare the map fields using map reflection // instead of sync to repeated. bool CompareMapFieldByMapReflection(const Message& message1, - const Message& message2, + const Message& message2, int unpacked_any, const FieldDescriptor* field, std::vector* parent_fields, DefaultFieldComparator* comparator); // Shorthand for CompareFieldValueUsingParentFields with NULL parent_fields. bool CompareFieldValue(const Message& message1, const Message& message2, - const FieldDescriptor* field, int index1, int index2); + int unpacked_any, const FieldDescriptor* field, + int index1, int index2); // Compares the specified field on the two messages, returning // true if they are the same, false otherwise. For repeated fields, @@ -826,7 +866,7 @@ class PROTOBUF_EXPORT MessageDifferencer { // To avoid confusing users you should not set it to NULL unless you modified // Reporter to handle the change of parent_fields correctly. bool CompareFieldValueUsingParentFields( - const Message& message1, const Message& message2, + const Message& message1, const Message& message2, int unpacked_any, const FieldDescriptor* field, int index1, int index2, std::vector* parent_fields); @@ -842,7 +882,7 @@ class PROTOBUF_EXPORT MessageDifferencer { // elements are equal. bool IsMatch(const FieldDescriptor* repeated_field, const MapKeyComparator* key_comparator, const Message* message1, - const Message* message2, + const Message* message2, int unpacked_any, const std::vector& parent_fields, Reporter* reporter, int index1, int index2); @@ -890,7 +930,7 @@ class PROTOBUF_EXPORT MessageDifferencer { // that the comparison succeeds when this method returns true (you need to // double-check in this case). bool MatchRepeatedFieldIndices( - const Message& message1, const Message& message2, + const Message& message1, const Message& message2, int unpacked_any, const FieldDescriptor* repeated_field, const MapKeyComparator* key_comparator, const std::vector& parent_fields, @@ -931,7 +971,7 @@ class PROTOBUF_EXPORT MessageDifferencer { std::vector owned_key_comparators_; FieldKeyComparatorMap map_field_key_comparator_; MapEntryKeyComparator map_entry_key_comparator_; - std::vector ignore_criteria_; + std::vector> ignore_criteria_; // Reused multiple times in RetrieveFields to avoid extra allocations std::vector tmp_message_fields_; diff --git a/src/google/protobuf/util/type_resolver_util.cc b/src/google/protobuf/util/type_resolver_util.cc index 49ae2d31c4..cd01d87a5a 100644 --- a/src/google/protobuf/util/type_resolver_util.cc +++ b/src/google/protobuf/util/type_resolver_util.cc @@ -38,7 +38,6 @@ #include "absl/status/status.h" #include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" -#include "google/protobuf/util/internal/utility.h" #include "google/protobuf/util/type_resolver.h" // clang-format off diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc index d9d2913051..e65dad0ca5 100644 --- a/src/google/protobuf/wire_format.cc +++ b/src/google/protobuf/wire_format.cc @@ -43,6 +43,7 @@ #include "google/protobuf/io/coded_stream.h" #include "google/protobuf/io/zero_copy_stream.h" #include "google/protobuf/io/zero_copy_stream_impl.h" +#include "absl/strings/cord.h" #include "google/protobuf/descriptor.h" #include "google/protobuf/descriptor.pb.h" #include "google/protobuf/dynamic_message.h" diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc index 7241a9eba1..089b0bc482 100644 --- a/src/google/protobuf/wire_format_lite.cc +++ b/src/google/protobuf/wire_format_lite.cc @@ -44,6 +44,7 @@ #include "google/protobuf/io/coded_stream.h" #include "google/protobuf/io/zero_copy_stream.h" #include "google/protobuf/io/zero_copy_stream_impl_lite.h" +#include "absl/strings/cord.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" @@ -621,7 +622,7 @@ void PrintUTF8ErrorLog(absl::string_view message_name, bool WireFormatLite::VerifyUtf8String(const char* data, int size, Operation op, const char* field_name) { - if (!IsStructurallyValidUTF8(data, size)) { + if (!::google::protobuf::internal::IsStructurallyValidUTF8(data, size)) { const char* operation_str = nullptr; switch (op) { case PARSE: diff --git a/src/google/protobuf/wire_format_unittest.inc b/src/google/protobuf/wire_format_unittest.inc index 6224ae7fa3..6a3c5bbfc4 100644 --- a/src/google/protobuf/wire_format_unittest.inc +++ b/src/google/protobuf/wire_format_unittest.inc @@ -45,6 +45,7 @@ #include #include "absl/base/casts.h" #include "google/protobuf/stubs/logging.h" +#include "absl/strings/cord.h" #include "absl/strings/match.h" #include "google/protobuf/dynamic_message.h" #include "google/protobuf/test_util2.h" diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h index a7af36d7d1..4f5684642e 100644 --- a/src/google/protobuf/wrappers.pb.h +++ b/src/google/protobuf/wrappers.pb.h @@ -15,7 +15,7 @@ #error "your headers." #endif // PROTOBUF_VERSION -#if 3021006 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021007 < PROTOBUF_MIN_PROTOC_VERSION #error "This file was generated by an older version of protoc which is" #error "incompatible with your Protocol Buffer headers. Please" #error "regenerate this file with a newer version of protoc." diff --git a/third_party/googletest b/third_party/googletest index 5ec7f0c4a1..4c9a3bb62b 160000 --- a/third_party/googletest +++ b/third_party/googletest @@ -1 +1 @@ -Subproject commit 5ec7f0c4a113e2f18ac2c6cc7df51ad6afc24081 +Subproject commit 4c9a3bb62bf3ba1f1010bf96f9c8ed767b363774