blob: 96ea3f2b8cf88d2f50c159e953d7a272893690d2 [file] [log] [blame]
Feng Xiaoe96ff302015-06-15 18:21:48 -07001// 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 <google/protobuf/stubs/hash.h>
36#include <string>
37
38#include <google/protobuf/stubs/common.h>
39#include <google/protobuf/io/coded_stream.h>
40#include <google/protobuf/io/zero_copy_stream_impl.h>
41#include <google/protobuf/descriptor.h>
42#include <google/protobuf/util/internal/type_info.h>
43#include <google/protobuf/util/internal/datapiece.h>
44#include <google/protobuf/util/internal/error_listener.h>
Feng Xiaoe841bac2015-12-11 17:09:20 -080045#include <google/protobuf/util/internal/proto_writer.h>
Feng Xiaoe96ff302015-06-15 18:21:48 -070046#include <google/protobuf/util/internal/structured_objectwriter.h>
47#include <google/protobuf/util/type_resolver.h>
48#include <google/protobuf/stubs/bytestream.h>
49
50namespace google {
51namespace protobuf {
52namespace io {
53class CodedOutputStream;
54} // namespace io
55} // namespace protobuf
56
57
58namespace protobuf {
59class Type;
60class Field;
61} // namespace protobuf
62
63
64namespace protobuf {
65namespace util {
66namespace converter {
67
68class ObjectLocationTracker;
69
70// An ObjectWriter that can write protobuf bytes directly from writer events.
Feng Xiaoe841bac2015-12-11 17:09:20 -080071// This class supports all special types like Struct and Map. It uses
72// the ProtoWriter class to write raw proto bytes.
Feng Xiaoe96ff302015-06-15 18:21:48 -070073//
74// It also supports streaming.
Feng Xiaoe841bac2015-12-11 17:09:20 -080075class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter {
Feng Xiaoe96ff302015-06-15 18:21:48 -070076 public:
Jisi Liu3b3c8ab2016-03-30 11:39:59 -070077 // Options that control ProtoStreamObjectWriter class's behavior.
78 struct Options {
79 // Treats integer inputs in google.protobuf.Struct as strings. Normally,
80 // integer values are returned in double field "number_value" of
81 // google.protobuf.Struct. However, this can cause precision loss for
82 // int64/uint64 inputs. This option is provided for cases that want to
83 // preserve integer precision.
84 bool struct_integers_as_strings;
85
86 Options() : struct_integers_as_strings(false) {}
87
88 // Default instance of Options with all options set to defaults.
89 static const Options& Defaults() {
90 static Options defaults;
91 return defaults;
92 }
93 };
94
Feng Xiaoeee38b02015-08-22 18:25:48 -070095// Constructor. Does not take ownership of any parameter passed in.
Feng Xiaoe96ff302015-06-15 18:21:48 -070096 ProtoStreamObjectWriter(TypeResolver* type_resolver,
97 const google::protobuf::Type& type,
Jisi Liu3b3c8ab2016-03-30 11:39:59 -070098 strings::ByteSink* output, ErrorListener* listener,
99 const ProtoStreamObjectWriter::Options& options =
100 ProtoStreamObjectWriter::Options::Defaults());
Feng Xiaoe96ff302015-06-15 18:21:48 -0700101 virtual ~ProtoStreamObjectWriter();
102
103 // ObjectWriter methods.
104 virtual ProtoStreamObjectWriter* StartObject(StringPiece name);
105 virtual ProtoStreamObjectWriter* EndObject();
106 virtual ProtoStreamObjectWriter* StartList(StringPiece name);
107 virtual ProtoStreamObjectWriter* EndList();
Feng Xiaoe96ff302015-06-15 18:21:48 -0700108
109 // Renders a DataPiece 'value' into a field whose wire type is determined
110 // from the given field 'name'.
Feng Xiaoe841bac2015-12-11 17:09:20 -0800111 virtual ProtoStreamObjectWriter* RenderDataPiece(StringPiece name,
112 const DataPiece& value);
Feng Xiaoe96ff302015-06-15 18:21:48 -0700113
Feng Xiaoe841bac2015-12-11 17:09:20 -0800114 protected:
Feng Xiaoe96ff302015-06-15 18:21:48 -0700115 // Function that renders a well known type with modified behavior.
116 typedef util::Status (*TypeRenderer)(ProtoStreamObjectWriter*,
117 const DataPiece&);
118
119 // Handles writing Anys out using nested object writers and the like.
120 class LIBPROTOBUF_EXPORT AnyWriter {
121 public:
122 explicit AnyWriter(ProtoStreamObjectWriter* parent);
123 ~AnyWriter();
124
125 // Passes a StartObject call through to the Any writer.
126 void StartObject(StringPiece name);
127
128 // Passes an EndObject call through to the Any. Returns true if the any
129 // handled the EndObject call, false if the Any is now all done and is no
130 // longer needed.
131 bool EndObject();
132
133 // Passes a StartList call through to the Any writer.
134 void StartList(StringPiece name);
135
136 // Passes an EndList call through to the Any writer.
137 void EndList();
138
139 // Renders a data piece on the any.
140 void RenderDataPiece(StringPiece name, const DataPiece& value);
141
142 private:
143 // Handles starting up the any once we have a type.
144 void StartAny(const DataPiece& value);
145
146 // Writes the Any out to the parent writer in its serialized form.
147 void WriteAny();
148
149 // The parent of this writer, needed for various bits such as type info and
150 // the listeners.
151 ProtoStreamObjectWriter* parent_;
152
153 // The nested object writer, used to write events.
154 google::protobuf::scoped_ptr<ProtoStreamObjectWriter> ow_;
155
156 // The type_url_ that this Any represents.
157 string type_url_;
158
159 // Whether this any is invalid. This allows us to only report an invalid
160 // Any message a single time rather than every time we get a nested field.
161 bool invalid_;
162
163 // The output data and wrapping ByteSink.
164 string data_;
165 strings::StringByteSink output_;
166
167 // The depth within the Any, so we can track when we're done.
168 int depth_;
169
170 // True if the message type contained in Any has a special "value" message
171 // injected. This is true for well-known message types like Any or Struct.
172 bool has_injected_value_message_;
173 };
174
Feng Xiaoe841bac2015-12-11 17:09:20 -0800175 // Represents an item in a stack of items used to keep state between
176 // ObjectWrier events.
177 class LIBPROTOBUF_EXPORT Item : public BaseElement {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700178 public:
Feng Xiaoe841bac2015-12-11 17:09:20 -0800179 // Indicates the type of item.
180 enum ItemType {
181 MESSAGE, // Simple message
182 MAP, // Proto3 map type
183 ANY, // Proto3 Any type
Feng Xiaoe96ff302015-06-15 18:21:48 -0700184 };
185
Feng Xiaoe841bac2015-12-11 17:09:20 -0800186 // Constructor for the root item.
187 Item(ProtoStreamObjectWriter* enclosing, ItemType item_type,
188 bool is_placeholder, bool is_list);
Feng Xiaoe96ff302015-06-15 18:21:48 -0700189
Feng Xiaoe841bac2015-12-11 17:09:20 -0800190 // Constructor for a field of a message.
191 Item(Item* parent, ItemType item_type, bool is_placeholder, bool is_list);
Feng Xiaoe96ff302015-06-15 18:21:48 -0700192
Feng Xiaoe841bac2015-12-11 17:09:20 -0800193 virtual ~Item() {}
Feng Xiaoe96ff302015-06-15 18:21:48 -0700194
195 // These functions return true if the element type is corresponding to the
196 // type in function name.
Feng Xiaoe841bac2015-12-11 17:09:20 -0800197 bool IsMap() { return item_type_ == MAP; }
198 bool IsAny() { return item_type_ == ANY; }
Feng Xiaoe96ff302015-06-15 18:21:48 -0700199
200 AnyWriter* any() const { return any_.get(); }
201
Feng Xiaoe841bac2015-12-11 17:09:20 -0800202 virtual Item* parent() const {
203 return static_cast<Item*>(BaseElement::parent());
Feng Xiaoe96ff302015-06-15 18:21:48 -0700204 }
205
Jisi Liu46e8ff62015-10-05 11:59:43 -0700206 // Inserts map key into hash set if and only if the key did NOT already
207 // exist in hash set.
208 // The hash set (map_keys_) is ONLY used to keep track of map keys.
209 // Return true if insert successfully; returns false if the map key was
210 // already present.
211 bool InsertMapKeyIfNotPresent(StringPiece map_key);
212
Feng Xiaoe841bac2015-12-11 17:09:20 -0800213 bool is_placeholder() const { return is_placeholder_; }
214 bool is_list() const { return is_list_; }
215
Feng Xiaoe96ff302015-06-15 18:21:48 -0700216 private:
217 // Used for access to variables of the enclosing instance of
218 // ProtoStreamObjectWriter.
219 ProtoStreamObjectWriter* ow_;
220
221 // A writer for Any objects, handles all Any-related nonsense.
222 google::protobuf::scoped_ptr<AnyWriter> any_;
223
Feng Xiaoe96ff302015-06-15 18:21:48 -0700224 // The type of this element, see enum for permissible types.
Feng Xiaoe841bac2015-12-11 17:09:20 -0800225 ItemType item_type_;
Feng Xiaoeee38b02015-08-22 18:25:48 -0700226
Jisi Liu46e8ff62015-10-05 11:59:43 -0700227 // Set of map keys already seen for the type_. Used to validate incoming
228 // messages so no map key appears more than once.
Feng Xiao9659ea92015-11-02 12:39:27 -0800229 hash_set<string> map_keys_;
Jisi Liu46e8ff62015-10-05 11:59:43 -0700230
Feng Xiaoe841bac2015-12-11 17:09:20 -0800231 // Conveys whether this Item is a placeholder or not. Placeholder items are
232 // pushed to stack to account for special types.
233 bool is_placeholder_;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700234
Feng Xiaoe841bac2015-12-11 17:09:20 -0800235 // Conveys whether this Item is a list or not. This is used to send
236 // StartList or EndList calls to underlying ObjectWriter.
237 bool is_list_;
238
239 GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Item);
Feng Xiaoe96ff302015-06-15 18:21:48 -0700240 };
241
Feng Xiaoeee38b02015-08-22 18:25:48 -0700242 ProtoStreamObjectWriter(const TypeInfo* typeinfo,
Feng Xiaoe96ff302015-06-15 18:21:48 -0700243 const google::protobuf::Type& type,
244 strings::ByteSink* output, ErrorListener* listener);
245
Feng Xiaoe96ff302015-06-15 18:21:48 -0700246 // Returns true if the field is a map.
247 bool IsMap(const google::protobuf::Field& field);
248
249 // Returns true if the field is an any.
250 bool IsAny(const google::protobuf::Field& field);
251
Feng Xiaoe841bac2015-12-11 17:09:20 -0800252 // Returns true if the field is google.protobuf.Struct.
253 bool IsStruct(const google::protobuf::Field& field);
Feng Xiaoe96ff302015-06-15 18:21:48 -0700254
Feng Xiaoe841bac2015-12-11 17:09:20 -0800255 // Returns true if the field is google.protobuf.Value.
256 bool IsStructValue(const google::protobuf::Field& field);
Jisi Liu46e8ff62015-10-05 11:59:43 -0700257
Feng Xiaoe841bac2015-12-11 17:09:20 -0800258 // Returns true if the field is google.protobuf.ListValue.
259 bool IsStructListValue(const google::protobuf::Field& field);
Feng Xiaoe96ff302015-06-15 18:21:48 -0700260
261 // Renders google.protobuf.Value in struct.proto. It picks the right oneof
262 // type based on value's type.
263 static util::Status RenderStructValue(ProtoStreamObjectWriter* ow,
264 const DataPiece& value);
265
266 // Renders google.protobuf.Timestamp value.
267 static util::Status RenderTimestamp(ProtoStreamObjectWriter* ow,
268 const DataPiece& value);
269
270 // Renders google.protobuf.FieldMask value.
271 static util::Status RenderFieldMask(ProtoStreamObjectWriter* ow,
272 const DataPiece& value);
273
274 // Renders google.protobuf.Duration value.
275 static util::Status RenderDuration(ProtoStreamObjectWriter* ow,
276 const DataPiece& value);
277
278 // Renders wrapper message types for primitive types in
279 // google/protobuf/wrappers.proto.
280 static util::Status RenderWrapperType(ProtoStreamObjectWriter* ow,
281 const DataPiece& value);
282
Jisi Liu09778152015-08-25 22:01:12 -0700283 static void InitRendererMap();
284 static void DeleteRendererMap();
Feng Xiaoe96ff302015-06-15 18:21:48 -0700285 static TypeRenderer* FindTypeRenderer(const string& type_url);
286
Jisi Liu46e8ff62015-10-05 11:59:43 -0700287 // Returns true if the map key for type_ is not duplicated key.
288 // If map key is duplicated key, this function returns false.
Feng Xiaoe841bac2015-12-11 17:09:20 -0800289 // Note that caller should make sure that the current proto element (current_)
Jisi Liu46e8ff62015-10-05 11:59:43 -0700290 // is of element type MAP or STRUCT_MAP.
291 // It also calls the appropriate error callback and unnormalzied_name is used
292 // for error string.
293 bool ValidMapKey(StringPiece unnormalized_name);
294
Feng Xiaoe841bac2015-12-11 17:09:20 -0800295 // Pushes an item on to the stack. Also calls either StartObject or StartList
296 // on the underlying ObjectWriter depending on whether is_list is false or
297 // not.
298 // is_placeholder conveys whether the item is a placeholder item or not.
299 // Placeholder items are pushed when adding auxillary types' StartObject or
300 // StartList calls.
301 void Push(StringPiece name, Item::ItemType item_type, bool is_placeholder,
302 bool is_list);
303
304 // Pops items from the stack. All placeholder items are popped until a
305 // non-placeholder item is found.
306 void Pop();
307
308 // Pops one element from the stack. Calls EndObject() or EndList() on the
309 // underlying ObjectWriter depending on the value of is_list_.
310 void PopOneElement();
311
312 private:
313 // Helper functions to create the map and find functions responsible for
314 // rendering well known types, keyed by type URL.
315 static hash_map<string, TypeRenderer>* renderers_;
316
Feng Xiaoe96ff302015-06-15 18:21:48 -0700317 // Variables for describing the structure of the input tree:
318 // master_type_: descriptor for the whole protobuf message.
Feng Xiaoe96ff302015-06-15 18:21:48 -0700319 const google::protobuf::Type& master_type_;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700320
Feng Xiaoe841bac2015-12-11 17:09:20 -0800321 // The current element, variable for internal state processing.
322 google::protobuf::scoped_ptr<Item> current_;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700323
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700324 // Reference to the options that control this class's behavior.
325 const ProtoStreamObjectWriter::Options options_;
326
Feng Xiaoe96ff302015-06-15 18:21:48 -0700327 GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectWriter);
328};
329
330} // namespace converter
331} // namespace util
332} // namespace protobuf
333
334} // namespace google
335#endif // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__