1 #include "absl/log/absl_check.h" 2 // Protocol Buffers - Google's data interchange format 3 // Copyright 2008 Google Inc. All rights reserved. 4 // 5 // Use of this source code is governed by a BSD-style 6 // license that can be found in the LICENSE file or at 7 // https://developers.google.com/open-source/licenses/bsd 8 9 #ifndef GOOGLE_PROTOBUF_UITL_UNTYPED_MESSAGE_H__ 10 #define GOOGLE_PROTOBUF_UITL_UNTYPED_MESSAGE_H__ 11 12 #include <cstddef> 13 #include <cstdint> 14 #include <memory> 15 #include <string> 16 #include <utility> 17 #include <vector> 18 19 #include "google/protobuf/type.pb.h" 20 #include "absl/container/flat_hash_map.h" 21 #include "absl/status/status.h" 22 #include "absl/strings/str_format.h" 23 #include "absl/strings/string_view.h" 24 #include "absl/types/optional.h" 25 #include "absl/types/span.h" 26 #include "absl/types/variant.h" 27 #include "google/protobuf/descriptor.h" 28 #include "google/protobuf/dynamic_message.h" 29 #include "google/protobuf/io/coded_stream.h" 30 #include "google/protobuf/message.h" 31 #include "google/protobuf/util/type_resolver.h" 32 #include "google/protobuf/wire_format.h" 33 #include "google/protobuf/wire_format_lite.h" 34 #include "google/protobuf/stubs/status_macros.h" 35 36 // Must be included last. 37 #include "google/protobuf/port_def.inc" 38 39 namespace google { 40 namespace protobuf { 41 namespace json_internal { 42 struct SizeVisitor { 43 template <typename T> operatorSizeVisitor44 size_t operator()(const std::vector<T>& x) { 45 return x.size(); 46 } 47 48 template <typename T> operatorSizeVisitor49 size_t operator()(const T& x) { 50 return 1; 51 } 52 }; 53 54 // A DescriptorPool-like type for caching lookups from a TypeResolver. 55 // 56 // This type and all of its nested types are thread-hostile. 57 class ResolverPool { 58 public: 59 class Message; 60 class Enum; 61 class Field { 62 public: 63 Field(const Field&) = delete; 64 Field& operator=(const Field&) = delete; 65 66 absl::StatusOr<const Message*> MessageType() const; 67 absl::StatusOr<const Enum*> EnumType() const; 68 parent()69 const Message& parent() const { return *parent_; } proto()70 const google::protobuf::Field& proto() const { return *raw_; } 71 72 private: 73 friend class ResolverPool; 74 75 Field() = default; 76 77 ResolverPool* pool_ = nullptr; 78 const google::protobuf::Field* raw_ = nullptr; 79 const Message* parent_ = nullptr; 80 mutable const void* type_ = nullptr; 81 }; 82 83 class Message { 84 public: 85 Message(const Message&) = delete; 86 Message& operator=(const Message&) = delete; 87 88 absl::Span<const Field> FieldsByIndex() const; 89 const Field* FindField(absl::string_view name) const; 90 const Field* FindField(int32_t number) const; 91 proto()92 const google::protobuf::Type& proto() const { return raw_; } pool()93 ResolverPool* pool() const { return pool_; } 94 95 private: 96 friend class ResolverPool; 97 Message(ResolverPool * pool)98 explicit Message(ResolverPool* pool) : pool_(pool) {} 99 100 ResolverPool* pool_; 101 google::protobuf::Type raw_; 102 mutable std::unique_ptr<Field[]> fields_; 103 mutable absl::flat_hash_map<absl::string_view, const Field*> 104 fields_by_name_; 105 mutable absl::flat_hash_map<int32_t, const Field*> fields_by_number_; 106 }; 107 108 class Enum { 109 public: 110 Enum(const Enum&) = delete; 111 Enum& operator=(const Enum&) = delete; 112 proto()113 const google::protobuf::Enum& proto() const { return raw_; } pool()114 ResolverPool* pool() const { return pool_; } 115 116 private: 117 friend class ResolverPool; 118 Enum(ResolverPool * pool)119 explicit Enum(ResolverPool* pool) : pool_(pool) {} 120 121 ResolverPool* pool_; 122 google::protobuf::Enum raw_; 123 mutable absl::flat_hash_map<absl::string_view, google::protobuf::EnumValue*> 124 values_; 125 }; 126 ResolverPool(google::protobuf::util::TypeResolver * resolver)127 explicit ResolverPool(google::protobuf::util::TypeResolver* resolver) 128 : resolver_(resolver) {} 129 130 ResolverPool(const ResolverPool&) = delete; 131 ResolverPool& operator=(const ResolverPool&) = delete; 132 133 absl::StatusOr<const Message*> FindMessage(absl::string_view url); 134 absl::StatusOr<const Enum*> FindEnum(absl::string_view url); 135 136 private: 137 absl::flat_hash_map<std::string, std::unique_ptr<Message>> messages_; 138 absl::flat_hash_map<std::string, std::unique_ptr<Enum>> enums_; 139 google::protobuf::util::TypeResolver* resolver_; 140 }; 141 142 // A parsed wire-format proto that uses TypeReslover for parsing. 143 // 144 // This type is an implementation detail of the JSON parser. 145 class UntypedMessage final { 146 public: 147 // New nominal type instead of `bool` to avoid vector<bool> shenanigans. 148 enum Bool : unsigned char { kTrue, kFalse }; 149 using Value = absl::variant<Bool, int32_t, uint32_t, int64_t, uint64_t, float, 150 double, std::string, UntypedMessage, 151 // 152 std::vector<Bool>, std::vector<int32_t>, 153 std::vector<uint32_t>, std::vector<int64_t>, 154 std::vector<uint64_t>, std::vector<float>, 155 std::vector<double>, std::vector<std::string>, 156 std::vector<UntypedMessage>>; 157 158 UntypedMessage(const UntypedMessage&) = delete; 159 UntypedMessage& operator=(const UntypedMessage&) = delete; 160 UntypedMessage(UntypedMessage&&) = default; 161 UntypedMessage& operator=(UntypedMessage&&) = default; 162 163 // Tries to parse a proto with the given descriptor from an input stream. ParseFromStream(const ResolverPool::Message * desc,io::CodedInputStream & stream)164 static absl::StatusOr<UntypedMessage> ParseFromStream( 165 const ResolverPool::Message* desc, io::CodedInputStream& stream) { 166 UntypedMessage msg(std::move(desc)); 167 RETURN_IF_ERROR(msg.Decode(stream)); 168 return std::move(msg); 169 } 170 171 // Returns the number of elements in a field by number. 172 // 173 // Optional fields are treated like repeated fields with one or zero elements. Count(int32_t field_number)174 size_t Count(int32_t field_number) const { 175 auto it = fields_.find(field_number); 176 if (it == fields_.end()) { 177 return 0; 178 } 179 180 return absl::visit(SizeVisitor{}, it->second); 181 } 182 183 // Returns the contents of a field by number. 184 // 185 // Optional fields are treated like repeated fields with one or zero elements. 186 // If the field is not set, returns an empty span. 187 // 188 // If `T` is the wrong type, this function crashes. 189 template <typename T> Get(int32_t field_number)190 absl::Span<const T> Get(int32_t field_number) const { 191 auto it = fields_.find(field_number); 192 if (it == fields_.end()) { 193 return {}; 194 } 195 196 if (auto* val = absl::get_if<T>(&it->second)) { 197 return absl::Span<const T>(val, 1); 198 } else if (auto* vec = absl::get_if<std::vector<T>>(&it->second)) { 199 return *vec; 200 } else { 201 ABSL_CHECK(false) << "wrong type for UntypedMessage::Get(" << field_number 202 << ")"; 203 return {}; // avoid compiler warning. 204 } 205 } 206 desc()207 const ResolverPool::Message& desc() const { return *desc_; } 208 209 private: 210 enum Cardinality { kSingular, kRepeated }; 211 UntypedMessage(const ResolverPool::Message * desc)212 explicit UntypedMessage(const ResolverPool::Message* desc) : desc_(desc) {} 213 214 absl::Status Decode(io::CodedInputStream& stream, 215 absl::optional<int32_t> current_group = absl::nullopt); 216 217 absl::Status DecodeVarint(io::CodedInputStream& stream, 218 const ResolverPool::Field& field); 219 absl::Status Decode64Bit(io::CodedInputStream& stream, 220 const ResolverPool::Field& field); 221 absl::Status Decode32Bit(io::CodedInputStream& stream, 222 const ResolverPool::Field& field); 223 absl::Status DecodeDelimited(io::CodedInputStream& stream, 224 const ResolverPool::Field& field); 225 226 template <typename T> 227 absl::Status InsertField(const ResolverPool::Field& field, T&& value); 228 229 const ResolverPool::Message* desc_; 230 absl::flat_hash_map<int32_t, Value> fields_; 231 }; 232 } // namespace json_internal 233 } // namespace protobuf 234 } // namespace google 235 236 #include "google/protobuf/port_undef.inc" 237 #endif // GOOGLE_PROTOBUF_UITL_UNTYPED_MESSAGE_H__ 238