// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd #ifndef GOOGLE_PROTOBUF_JSON_INTERNAL_PARSER_TRAITS_H__ #define GOOGLE_PROTOBUF_JSON_INTERNAL_PARSER_TRAITS_H__ #include #include #include #include #include #include #include #include "google/protobuf/type.pb.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/wire_format_lite.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 occurrence 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->SerializePartialAsString()); } else { msg.msg_->GetReflection()->SetString( msg.msg_, f, dynamic->SerializePartialAsString()); } 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_t 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_t 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__