• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 #ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__
32 #define GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__
33 
34 #include <deque>
35 #include <string>
36 #include <unordered_map>
37 #include <unordered_set>
38 
39 #include <google/protobuf/stubs/common.h>
40 #include <google/protobuf/type.pb.h>
41 #include <google/protobuf/io/coded_stream.h>
42 #include <google/protobuf/io/zero_copy_stream_impl.h>
43 #include <google/protobuf/descriptor.h>
44 #include <google/protobuf/util/internal/type_info.h>
45 #include <google/protobuf/util/internal/datapiece.h>
46 #include <google/protobuf/util/internal/error_listener.h>
47 #include <google/protobuf/util/internal/proto_writer.h>
48 #include <google/protobuf/util/internal/structured_objectwriter.h>
49 #include <google/protobuf/util/type_resolver.h>
50 #include <google/protobuf/stubs/bytestream.h>
51 #include <google/protobuf/stubs/hash.h>
52 
53 #include <google/protobuf/port_def.inc>
54 
55 namespace google {
56 namespace protobuf {
57 namespace util {
58 namespace converter {
59 
60 class ObjectLocationTracker;
61 
62 // An ObjectWriter that can write protobuf bytes directly from writer events.
63 // This class supports all special types like Struct and Map. It uses
64 // the ProtoWriter class to write raw proto bytes.
65 //
66 // It also supports streaming.
67 class PROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter {
68  public:
69   // Options that control ProtoStreamObjectWriter class's behavior.
70   struct Options {
71     // Treats numeric inputs in google.protobuf.Struct as strings. Normally,
72     // numeric values are returned in double field "number_value" of
73     // google.protobuf.Struct. However, this can cause precision loss for
74     // int64/uint64/double inputs. This option is provided for cases that want
75     // to preserve number precision.
76     //
77     // TODO(skarvaje): Rename to struct_numbers_as_strings as it covers double
78     // as well.
79     bool struct_integers_as_strings;
80 
81     // Not treat unknown fields as an error. If there is an unknown fields,
82     // just ignore it and continue to process the rest. Note that this doesn't
83     // apply to unknown enum values.
84     bool ignore_unknown_fields;
85 
86     // Ignore unknown enum values.
87     bool ignore_unknown_enum_values;
88 
89     // If true, check if enum name in camel case or without underscore matches
90     // the field name.
91     bool use_lower_camel_for_enums;
92 
93     // If true, check if enum name in UPPER_CASE matches the field name.
94     bool case_insensitive_enum_parsing;
95 
96     // If true, skips rendering the map entry if map value is null unless the
97     // value type is google.protobuf.NullType.
98     bool ignore_null_value_map_entry;
99 
100     // If true, accepts repeated key/value pair for a map proto field.
101     bool use_legacy_json_map_format;
102 
103     // If true, disable implicitly creating message list.
104     bool disable_implicit_message_list;
105 
106     // If true, suppress the error of implicitly creating message list when it
107     // is disabled.
108     bool suppress_implicit_message_list_error;
109 
110     // If true, suppress the error of rendering scalar field if the source is an
111     // object.
112     bool suppress_object_to_scalar_error;
113 
114     // If true, use the json name in missing fields errors.
115     bool use_json_name_in_missing_fields;
116 
OptionsOptions117     Options()
118         : struct_integers_as_strings(false),
119           ignore_unknown_fields(false),
120           ignore_unknown_enum_values(false),
121           use_lower_camel_for_enums(false),
122           case_insensitive_enum_parsing(false),
123           ignore_null_value_map_entry(false),
124           use_legacy_json_map_format(false),
125           disable_implicit_message_list(false),
126           suppress_implicit_message_list_error(false),
127           suppress_object_to_scalar_error(false),
128           use_json_name_in_missing_fields(false) {}
129 
130     // Default instance of Options with all options set to defaults.
DefaultsOptions131     static const Options& Defaults() {
132       static Options defaults;
133       return defaults;
134     }
135   };
136 
137   // Constructor. Does not take ownership of any parameter passed in.
138   ProtoStreamObjectWriter(TypeResolver* type_resolver,
139                           const google::protobuf::Type& type,
140                           strings::ByteSink* output, ErrorListener* listener,
141                           const ProtoStreamObjectWriter::Options& options =
142                               ProtoStreamObjectWriter::Options::Defaults());
143   ~ProtoStreamObjectWriter() override;
144 
145   // ObjectWriter methods.
146   ProtoStreamObjectWriter* StartObject(StringPiece name) override;
147   ProtoStreamObjectWriter* EndObject() override;
148   ProtoStreamObjectWriter* StartList(StringPiece name) override;
149   ProtoStreamObjectWriter* EndList() override;
150 
151   // Renders a DataPiece 'value' into a field whose wire type is determined
152   // from the given field 'name'.
153   ProtoStreamObjectWriter* RenderDataPiece(StringPiece name,
154                                            const DataPiece& data) override;
155 
156  protected:
157   // Function that renders a well known type with modified behavior.
158   typedef util::Status (*TypeRenderer)(ProtoStreamObjectWriter*,
159                                          const DataPiece&);
160 
161   // Handles writing Anys out using nested object writers and the like.
162   class PROTOBUF_EXPORT AnyWriter {
163    public:
164     explicit AnyWriter(ProtoStreamObjectWriter* parent);
165     ~AnyWriter();
166 
167     // Passes a StartObject call through to the Any writer.
168     void StartObject(StringPiece name);
169 
170     // Passes an EndObject call through to the Any. Returns true if the any
171     // handled the EndObject call, false if the Any is now all done and is no
172     // longer needed.
173     bool EndObject();
174 
175     // Passes a StartList call through to the Any writer.
176     void StartList(StringPiece name);
177 
178     // Passes an EndList call through to the Any writer.
179     void EndList();
180 
181     // Renders a data piece on the any.
182     void RenderDataPiece(StringPiece name, const DataPiece& value);
183 
184    private:
185     // Before the "@type" field is encountered, we store all incoming data
186     // into this Event struct and replay them after we get the "@type" field.
187     class PROTOBUF_EXPORT Event {
188      public:
189       enum Type {
190         START_OBJECT = 0,
191         END_OBJECT = 1,
192         START_LIST = 2,
193         END_LIST = 3,
194         RENDER_DATA_PIECE = 4,
195       };
196 
197       // Constructor for END_OBJECT and END_LIST events.
Event(Type type)198       explicit Event(Type type) : type_(type), value_(DataPiece::NullData()) {}
199 
200       // Constructor for START_OBJECT and START_LIST events.
Event(Type type,StringPiece name)201       explicit Event(Type type, StringPiece name)
202           : type_(type), name_(name), value_(DataPiece::NullData()) {}
203 
204       // Constructor for RENDER_DATA_PIECE events.
Event(StringPiece name,const DataPiece & value)205       explicit Event(StringPiece name, const DataPiece& value)
206           : type_(RENDER_DATA_PIECE), name_(name), value_(value) {
207         DeepCopy();
208       }
209 
Event(const Event & other)210       Event(const Event& other)
211           : type_(other.type_), name_(other.name_), value_(other.value_) {
212         DeepCopy();
213       }
214 
215       Event& operator=(const Event& other) {
216         type_ = other.type_;
217         name_ = other.name_;
218         value_ = other.value_;
219         DeepCopy();
220         return *this;
221       }
222 
223       void Replay(AnyWriter* writer) const;
224 
225      private:
226       void DeepCopy();
227 
228       Type type_;
229       std::string name_;
230       DataPiece value_;
231       std::string value_storage_;
232     };
233 
234     // Handles starting up the any once we have a type.
235     void StartAny(const DataPiece& value);
236 
237     // Writes the Any out to the parent writer in its serialized form.
238     void WriteAny();
239 
240     // The parent of this writer, needed for various bits such as type info and
241     // the listeners.
242     ProtoStreamObjectWriter* parent_;
243 
244     // The nested object writer, used to write events.
245     std::unique_ptr<ProtoStreamObjectWriter> ow_;
246 
247     // The type_url_ that this Any represents.
248     std::string type_url_;
249 
250     // Whether this any is invalid. This allows us to only report an invalid
251     // Any message a single time rather than every time we get a nested field.
252     bool invalid_;
253 
254     // The output data and wrapping ByteSink.
255     std::string data_;
256     strings::StringByteSink output_;
257 
258     // The depth within the Any, so we can track when we're done.
259     int depth_;
260 
261     // True if the type is a well-known type. Well-known types in Any
262     // has a special formatting:
263     // {
264     //   "@type": "type.googleapis.com/google.protobuf.XXX",
265     //   "value": <JSON representation of the type>,
266     // }
267     bool is_well_known_type_;
268     TypeRenderer* well_known_type_render_;
269 
270     // Store data before the "@type" field.
271     std::vector<Event> uninterpreted_events_;
272   };
273 
274   // Represents an item in a stack of items used to keep state between
275   // ObjectWrier events.
276   class PROTOBUF_EXPORT Item : public BaseElement {
277    public:
278     // Indicates the type of item.
279     enum ItemType {
280       MESSAGE,  // Simple message
281       MAP,      // Proto3 map type
282       ANY,      // Proto3 Any type
283     };
284 
285     // Constructor for the root item.
286     Item(ProtoStreamObjectWriter* enclosing, ItemType item_type,
287          bool is_placeholder, bool is_list);
288 
289     // Constructor for a field of a message.
290     Item(Item* parent, ItemType item_type, bool is_placeholder, bool is_list);
291 
~Item()292     ~Item() override {}
293 
294     // These functions return true if the element type is corresponding to the
295     // type in function name.
IsMap()296     bool IsMap() { return item_type_ == MAP; }
IsAny()297     bool IsAny() { return item_type_ == ANY; }
298 
any()299     AnyWriter* any() const { return any_.get(); }
300 
parent()301     Item* parent() const override {
302       return static_cast<Item*>(BaseElement::parent());
303     }
304 
305     // Inserts map key into hash set if and only if the key did NOT already
306     // exist in hash set.
307     // The hash set (map_keys_) is ONLY used to keep track of map keys.
308     // Return true if insert successfully; returns false if the map key was
309     // already present.
310     bool InsertMapKeyIfNotPresent(StringPiece map_key);
311 
is_placeholder()312     bool is_placeholder() const { return is_placeholder_; }
is_list()313     bool is_list() const { return is_list_; }
314 
315    private:
316     // Used for access to variables of the enclosing instance of
317     // ProtoStreamObjectWriter.
318     ProtoStreamObjectWriter* ow_;
319 
320     // A writer for Any objects, handles all Any-related nonsense.
321     std::unique_ptr<AnyWriter> any_;
322 
323     // The type of this element, see enum for permissible types.
324     ItemType item_type_;
325 
326     // Set of map keys already seen for the type_. Used to validate incoming
327     // messages so no map key appears more than once.
328     std::unique_ptr<std::unordered_set<std::string> > map_keys_;
329 
330     // Conveys whether this Item is a placeholder or not. Placeholder items are
331     // pushed to stack to account for special types.
332     bool is_placeholder_;
333 
334     // Conveys whether this Item is a list or not. This is used to send
335     // StartList or EndList calls to underlying ObjectWriter.
336     bool is_list_;
337 
338     GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Item);
339   };
340 
341   ProtoStreamObjectWriter(const TypeInfo* typeinfo,
342                           const google::protobuf::Type& type,
343                           strings::ByteSink* output, ErrorListener* listener);
344 
345   ProtoStreamObjectWriter(const TypeInfo* typeinfo,
346                           const google::protobuf::Type& type,
347                           strings::ByteSink* output, ErrorListener* listener,
348                           const ProtoStreamObjectWriter::Options& options);
349 
350   // Returns true if the field is a map.
351   inline bool IsMap(const google::protobuf::Field& field);
352 
353   // Returns true if the field is an any.
354   inline bool IsAny(const google::protobuf::Field& field);
355 
356   // Returns true if the field is google.protobuf.Struct.
357   inline bool IsStruct(const google::protobuf::Field& field);
358 
359   // Returns true if the field is google.protobuf.Value.
360   inline bool IsStructValue(const google::protobuf::Field& field);
361 
362   // Returns true if the field is google.protobuf.ListValue.
363   inline bool IsStructListValue(const google::protobuf::Field& field);
364 
365   // Renders google.protobuf.Value in struct.proto. It picks the right oneof
366   // type based on value's type.
367   static util::Status RenderStructValue(ProtoStreamObjectWriter* ow,
368                                           const DataPiece& data);
369 
370   // Renders google.protobuf.Timestamp value.
371   static util::Status RenderTimestamp(ProtoStreamObjectWriter* ow,
372                                         const DataPiece& data);
373 
374   // Renders google.protobuf.FieldMask value.
375   static util::Status RenderFieldMask(ProtoStreamObjectWriter* ow,
376                                         const DataPiece& data);
377 
378   // Renders google.protobuf.Duration value.
379   static util::Status RenderDuration(ProtoStreamObjectWriter* ow,
380                                        const DataPiece& data);
381 
382   // Renders wrapper message types for primitive types in
383   // google/protobuf/wrappers.proto.
384   static util::Status RenderWrapperType(ProtoStreamObjectWriter* ow,
385                                           const DataPiece& data);
386 
387   static void InitRendererMap();
388   static void DeleteRendererMap();
389   static TypeRenderer* FindTypeRenderer(const std::string& type_url);
390 
391   // Returns true if the map key for type_ is not duplicated key.
392   // If map key is duplicated key, this function returns false.
393   // Note that caller should make sure that the current proto element (current_)
394   // is of element type MAP or STRUCT_MAP.
395   // It also calls the appropriate error callback and unnormalzied_name is used
396   // for error string.
397   bool ValidMapKey(StringPiece unnormalized_name);
398 
399   // Pushes an item on to the stack. Also calls either StartObject or StartList
400   // on the underlying ObjectWriter depending on whether is_list is false or
401   // not.
402   // is_placeholder conveys whether the item is a placeholder item or not.
403   // Placeholder items are pushed when adding auxiliary types' StartObject or
404   // StartList calls.
405   void Push(StringPiece name, Item::ItemType item_type,
406             bool is_placeholder, bool is_list);
407 
408 
409   // Pops items from the stack. All placeholder items are popped until a
410   // non-placeholder item is found.
411   void Pop();
412 
413   // Pops one element from the stack. Calls EndObject() or EndList() on the
414   // underlying ObjectWriter depending on the value of is_list_.
415   void PopOneElement();
416 
417  private:
418   // Helper functions to create the map and find functions responsible for
419   // rendering well known types, keyed by type URL.
420   static std::unordered_map<std::string, TypeRenderer>* renderers_;
421 
422   // Variables for describing the structure of the input tree:
423   // master_type_: descriptor for the whole protobuf message.
424   const google::protobuf::Type& master_type_;
425 
426   // The current element, variable for internal state processing.
427   std::unique_ptr<Item> current_;
428 
429   // Reference to the options that control this class's behavior.
430   const ProtoStreamObjectWriter::Options options_;
431 
432   GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectWriter);
433 };
434 
435 }  // namespace converter
436 }  // namespace util
437 }  // namespace protobuf
438 }  // namespace google
439 
440 #include <google/protobuf/port_undef.inc>
441 
442 #endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__
443