1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
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
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.
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.
31 #ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__
32 #define GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__
36 #include <unordered_map>
37 #include <unordered_set>
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>
53 #include <google/protobuf/port_def.inc>
60 class ObjectLocationTracker;
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.
66 // It also supports streaming.
67 class PROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter {
69 // Options that control ProtoStreamObjectWriter class's behavior.
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.
77 // TODO(skarvaje): Rename to struct_numbers_as_strings as it covers double
79 bool struct_integers_as_strings;
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;
86 // Ignore unknown enum values.
87 bool ignore_unknown_enum_values;
89 // If true, check if enum name in camel case or without underscore matches
91 bool use_lower_camel_for_enums;
93 // If true, check if enum name in UPPER_CASE matches the field name.
94 bool case_insensitive_enum_parsing;
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;
101 : struct_integers_as_strings(false),
102 ignore_unknown_fields(false),
103 ignore_unknown_enum_values(false),
104 use_lower_camel_for_enums(false),
105 case_insensitive_enum_parsing(false),
106 ignore_null_value_map_entry(false) {}
108 // Default instance of Options with all options set to defaults.
109 static const Options& Defaults() {
110 static Options defaults;
115 // Constructor. Does not take ownership of any parameter passed in.
116 ProtoStreamObjectWriter(TypeResolver* type_resolver,
117 const google::protobuf::Type& type,
118 strings::ByteSink* output, ErrorListener* listener,
119 const ProtoStreamObjectWriter::Options& options =
120 ProtoStreamObjectWriter::Options::Defaults());
121 ~ProtoStreamObjectWriter() override;
123 // ObjectWriter methods.
124 ProtoStreamObjectWriter* StartObject(StringPiece name) override;
125 ProtoStreamObjectWriter* EndObject() override;
126 ProtoStreamObjectWriter* StartList(StringPiece name) override;
127 ProtoStreamObjectWriter* EndList() override;
129 // Renders a DataPiece 'value' into a field whose wire type is determined
130 // from the given field 'name'.
131 ProtoStreamObjectWriter* RenderDataPiece(StringPiece name,
132 const DataPiece& data) override;
135 // Function that renders a well known type with modified behavior.
136 typedef util::Status (*TypeRenderer)(ProtoStreamObjectWriter*,
139 // Handles writing Anys out using nested object writers and the like.
140 class PROTOBUF_EXPORT AnyWriter {
142 explicit AnyWriter(ProtoStreamObjectWriter* parent);
145 // Passes a StartObject call through to the Any writer.
146 void StartObject(StringPiece name);
148 // Passes an EndObject call through to the Any. Returns true if the any
149 // handled the EndObject call, false if the Any is now all done and is no
153 // Passes a StartList call through to the Any writer.
154 void StartList(StringPiece name);
156 // Passes an EndList call through to the Any writer.
159 // Renders a data piece on the any.
160 void RenderDataPiece(StringPiece name, const DataPiece& value);
163 // Before the "@type" field is encountered, we store all incoming data
164 // into this Event struct and replay them after we get the "@type" field.
165 class PROTOBUF_EXPORT Event {
172 RENDER_DATA_PIECE = 4,
175 // Constructor for END_OBJECT and END_LIST events.
176 explicit Event(Type type) : type_(type), value_(DataPiece::NullData()) {}
178 // Constructor for START_OBJECT and START_LIST events.
179 explicit Event(Type type, StringPiece name)
180 : type_(type), name_(name), value_(DataPiece::NullData()) {}
182 // Constructor for RENDER_DATA_PIECE events.
183 explicit Event(StringPiece name, const DataPiece& value)
184 : type_(RENDER_DATA_PIECE), name_(name), value_(value) {
188 Event(const Event& other)
189 : type_(other.type_), name_(other.name_), value_(other.value_) {
193 Event& operator=(const Event& other) {
196 value_ = other.value_;
201 void Replay(AnyWriter* writer) const;
209 std::string value_storage_;
212 // Handles starting up the any once we have a type.
213 void StartAny(const DataPiece& value);
215 // Writes the Any out to the parent writer in its serialized form.
218 // The parent of this writer, needed for various bits such as type info and
220 ProtoStreamObjectWriter* parent_;
222 // The nested object writer, used to write events.
223 std::unique_ptr<ProtoStreamObjectWriter> ow_;
225 // The type_url_ that this Any represents.
226 std::string type_url_;
228 // Whether this any is invalid. This allows us to only report an invalid
229 // Any message a single time rather than every time we get a nested field.
232 // The output data and wrapping ByteSink.
234 strings::StringByteSink output_;
236 // The depth within the Any, so we can track when we're done.
239 // True if the type is a well-known type. Well-known types in Any
240 // has a special formating:
242 // "@type": "type.googleapis.com/google.protobuf.XXX",
243 // "value": <JSON representation of the type>,
245 bool is_well_known_type_;
246 TypeRenderer* well_known_type_render_;
248 // Store data before the "@type" field.
249 std::vector<Event> uninterpreted_events_;
252 // Represents an item in a stack of items used to keep state between
253 // ObjectWrier events.
254 class PROTOBUF_EXPORT Item : public BaseElement {
256 // Indicates the type of item.
258 MESSAGE, // Simple message
259 MAP, // Proto3 map type
260 ANY, // Proto3 Any type
263 // Constructor for the root item.
264 Item(ProtoStreamObjectWriter* enclosing, ItemType item_type,
265 bool is_placeholder, bool is_list);
267 // Constructor for a field of a message.
268 Item(Item* parent, ItemType item_type, bool is_placeholder, bool is_list);
272 // These functions return true if the element type is corresponding to the
273 // type in function name.
274 bool IsMap() { return item_type_ == MAP; }
275 bool IsAny() { return item_type_ == ANY; }
277 AnyWriter* any() const { return any_.get(); }
279 Item* parent() const override {
280 return static_cast<Item*>(BaseElement::parent());
283 // Inserts map key into hash set if and only if the key did NOT already
284 // exist in hash set.
285 // The hash set (map_keys_) is ONLY used to keep track of map keys.
286 // Return true if insert successfully; returns false if the map key was
288 bool InsertMapKeyIfNotPresent(StringPiece map_key);
290 bool is_placeholder() const { return is_placeholder_; }
291 bool is_list() const { return is_list_; }
294 // Used for access to variables of the enclosing instance of
295 // ProtoStreamObjectWriter.
296 ProtoStreamObjectWriter* ow_;
298 // A writer for Any objects, handles all Any-related nonsense.
299 std::unique_ptr<AnyWriter> any_;
301 // The type of this element, see enum for permissible types.
304 // Set of map keys already seen for the type_. Used to validate incoming
305 // messages so no map key appears more than once.
306 std::unique_ptr<std::unordered_set<std::string> > map_keys_;
308 // Conveys whether this Item is a placeholder or not. Placeholder items are
309 // pushed to stack to account for special types.
310 bool is_placeholder_;
312 // Conveys whether this Item is a list or not. This is used to send
313 // StartList or EndList calls to underlying ObjectWriter.
316 GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Item);
319 ProtoStreamObjectWriter(const TypeInfo* typeinfo,
320 const google::protobuf::Type& type,
321 strings::ByteSink* output, ErrorListener* listener);
323 ProtoStreamObjectWriter(const TypeInfo* typeinfo,
324 const google::protobuf::Type& type,
325 strings::ByteSink* output, ErrorListener* listener,
326 const ProtoStreamObjectWriter::Options& options);
328 // Returns true if the field is a map.
329 inline bool IsMap(const google::protobuf::Field& field);
331 // Returns true if the field is an any.
332 inline bool IsAny(const google::protobuf::Field& field);
334 // Returns true if the field is google.protobuf.Struct.
335 inline bool IsStruct(const google::protobuf::Field& field);
337 // Returns true if the field is google.protobuf.Value.
338 inline bool IsStructValue(const google::protobuf::Field& field);
340 // Returns true if the field is google.protobuf.ListValue.
341 inline bool IsStructListValue(const google::protobuf::Field& field);
343 // Renders google.protobuf.Value in struct.proto. It picks the right oneof
344 // type based on value's type.
345 static util::Status RenderStructValue(ProtoStreamObjectWriter* ow,
346 const DataPiece& value);
348 // Renders google.protobuf.Timestamp value.
349 static util::Status RenderTimestamp(ProtoStreamObjectWriter* ow,
350 const DataPiece& value);
352 // Renders google.protobuf.FieldMask value.
353 static util::Status RenderFieldMask(ProtoStreamObjectWriter* ow,
354 const DataPiece& value);
356 // Renders google.protobuf.Duration value.
357 static util::Status RenderDuration(ProtoStreamObjectWriter* ow,
358 const DataPiece& value);
360 // Renders wrapper message types for primitive types in
361 // google/protobuf/wrappers.proto.
362 static util::Status RenderWrapperType(ProtoStreamObjectWriter* ow,
363 const DataPiece& value);
365 static void InitRendererMap();
366 static void DeleteRendererMap();
367 static TypeRenderer* FindTypeRenderer(const std::string& type_url);
369 // Returns true if the map key for type_ is not duplicated key.
370 // If map key is duplicated key, this function returns false.
371 // Note that caller should make sure that the current proto element (current_)
372 // is of element type MAP or STRUCT_MAP.
373 // It also calls the appropriate error callback and unnormalzied_name is used
375 bool ValidMapKey(StringPiece unnormalized_name);
377 // Pushes an item on to the stack. Also calls either StartObject or StartList
378 // on the underlying ObjectWriter depending on whether is_list is false or
380 // is_placeholder conveys whether the item is a placeholder item or not.
381 // Placeholder items are pushed when adding auxillary types' StartObject or
383 void Push(StringPiece name, Item::ItemType item_type,
384 bool is_placeholder, bool is_list);
386 // Pops items from the stack. All placeholder items are popped until a
387 // non-placeholder item is found.
390 // Pops one element from the stack. Calls EndObject() or EndList() on the
391 // underlying ObjectWriter depending on the value of is_list_.
392 void PopOneElement();
395 // Helper functions to create the map and find functions responsible for
396 // rendering well known types, keyed by type URL.
397 static std::unordered_map<std::string, TypeRenderer>* renderers_;
399 // Variables for describing the structure of the input tree:
400 // master_type_: descriptor for the whole protobuf message.
401 const google::protobuf::Type& master_type_;
403 // The current element, variable for internal state processing.
404 std::unique_ptr<Item> current_;
406 // Reference to the options that control this class's behavior.
407 const ProtoStreamObjectWriter::Options options_;
409 GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectWriter);
412 } // namespace converter
414 } // namespace protobuf
415 } // namespace google
417 #include <google/protobuf/port_undef.inc>
419 #endif // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__