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