• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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