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 <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>
45#include <google/protobuf/util/internal/proto_writer.h>
46#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.
71// This class supports all special types like Struct and Map. It uses
72// the ProtoWriter class to write raw proto bytes.
73//
74// It also supports streaming.
75class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter {
76 public:
77  // 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
95// Constructor. Does not take ownership of any parameter passed in.
96  ProtoStreamObjectWriter(TypeResolver* type_resolver,
97                          const google::protobuf::Type& type,
98                          strings::ByteSink* output, ErrorListener* listener,
99                          const ProtoStreamObjectWriter::Options& options =
100                              ProtoStreamObjectWriter::Options::Defaults());
101  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();
108
109  // Renders a DataPiece 'value' into a field whose wire type is determined
110  // from the given field 'name'.
111  virtual ProtoStreamObjectWriter* RenderDataPiece(StringPiece name,
112                                                   const DataPiece& value);
113
114 protected:
115  // 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 type is a well-known type. Well-known types in Any
171    // has a special formating:
172    // {
173    //   "@type": "type.googleapis.com/google.protobuf.XXX",
174    //   "value": <JSON representation of the type>,
175    // }
176    bool is_well_known_type_;
177    TypeRenderer* well_known_type_render_;
178  };
179
180  // Represents an item in a stack of items used to keep state between
181  // ObjectWrier events.
182  class LIBPROTOBUF_EXPORT Item : public BaseElement {
183   public:
184    // Indicates the type of item.
185    enum ItemType {
186      MESSAGE,  // Simple message
187      MAP,      // Proto3 map type
188      ANY,      // Proto3 Any type
189    };
190
191    // Constructor for the root item.
192    Item(ProtoStreamObjectWriter* enclosing, ItemType item_type,
193         bool is_placeholder, bool is_list);
194
195    // Constructor for a field of a message.
196    Item(Item* parent, ItemType item_type, bool is_placeholder, bool is_list);
197
198    virtual ~Item() {}
199
200    // These functions return true if the element type is corresponding to the
201    // type in function name.
202    bool IsMap() { return item_type_ == MAP; }
203    bool IsAny() { return item_type_ == ANY; }
204
205    AnyWriter* any() const { return any_.get(); }
206
207    virtual Item* parent() const {
208      return static_cast<Item*>(BaseElement::parent());
209    }
210
211    // Inserts map key into hash set if and only if the key did NOT already
212    // exist in hash set.
213    // The hash set (map_keys_) is ONLY used to keep track of map keys.
214    // Return true if insert successfully; returns false if the map key was
215    // already present.
216    bool InsertMapKeyIfNotPresent(StringPiece map_key);
217
218    bool is_placeholder() const { return is_placeholder_; }
219    bool is_list() const { return is_list_; }
220
221   private:
222    // Used for access to variables of the enclosing instance of
223    // ProtoStreamObjectWriter.
224    ProtoStreamObjectWriter* ow_;
225
226    // A writer for Any objects, handles all Any-related nonsense.
227    google::protobuf::scoped_ptr<AnyWriter> any_;
228
229    // The type of this element, see enum for permissible types.
230    ItemType item_type_;
231
232    // Set of map keys already seen for the type_. Used to validate incoming
233    // messages so no map key appears more than once.
234    hash_set<string> map_keys_;
235
236    // Conveys whether this Item is a placeholder or not. Placeholder items are
237    // pushed to stack to account for special types.
238    bool is_placeholder_;
239
240    // Conveys whether this Item is a list or not. This is used to send
241    // StartList or EndList calls to underlying ObjectWriter.
242    bool is_list_;
243
244    GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Item);
245  };
246
247  ProtoStreamObjectWriter(const TypeInfo* typeinfo,
248                          const google::protobuf::Type& type,
249                          strings::ByteSink* output, ErrorListener* listener);
250
251  // Returns true if the field is a map.
252  bool IsMap(const google::protobuf::Field& field);
253
254  // Returns true if the field is an any.
255  bool IsAny(const google::protobuf::Field& field);
256
257  // Returns true if the field is google.protobuf.Struct.
258  bool IsStruct(const google::protobuf::Field& field);
259
260  // Returns true if the field is google.protobuf.Value.
261  bool IsStructValue(const google::protobuf::Field& field);
262
263  // Returns true if the field is google.protobuf.ListValue.
264  bool IsStructListValue(const google::protobuf::Field& field);
265
266  // Renders google.protobuf.Value in struct.proto. It picks the right oneof
267  // type based on value's type.
268  static util::Status RenderStructValue(ProtoStreamObjectWriter* ow,
269                                          const DataPiece& value);
270
271  // Renders google.protobuf.Timestamp value.
272  static util::Status RenderTimestamp(ProtoStreamObjectWriter* ow,
273                                        const DataPiece& value);
274
275  // Renders google.protobuf.FieldMask value.
276  static util::Status RenderFieldMask(ProtoStreamObjectWriter* ow,
277                                        const DataPiece& value);
278
279  // Renders google.protobuf.Duration value.
280  static util::Status RenderDuration(ProtoStreamObjectWriter* ow,
281                                       const DataPiece& value);
282
283  // Renders wrapper message types for primitive types in
284  // google/protobuf/wrappers.proto.
285  static util::Status RenderWrapperType(ProtoStreamObjectWriter* ow,
286                                          const DataPiece& value);
287
288  static void InitRendererMap();
289  static void DeleteRendererMap();
290  static TypeRenderer* FindTypeRenderer(const string& type_url);
291
292  // Returns true if the map key for type_ is not duplicated key.
293  // If map key is duplicated key, this function returns false.
294  // Note that caller should make sure that the current proto element (current_)
295  // is of element type MAP or STRUCT_MAP.
296  // It also calls the appropriate error callback and unnormalzied_name is used
297  // for error string.
298  bool ValidMapKey(StringPiece unnormalized_name);
299
300  // Pushes an item on to the stack. Also calls either StartObject or StartList
301  // on the underlying ObjectWriter depending on whether is_list is false or
302  // not.
303  // is_placeholder conveys whether the item is a placeholder item or not.
304  // Placeholder items are pushed when adding auxillary types' StartObject or
305  // StartList calls.
306  void Push(StringPiece name, Item::ItemType item_type, bool is_placeholder,
307            bool is_list);
308
309  // Pops items from the stack. All placeholder items are popped until a
310  // non-placeholder item is found.
311  void Pop();
312
313  // Pops one element from the stack. Calls EndObject() or EndList() on the
314  // underlying ObjectWriter depending on the value of is_list_.
315  void PopOneElement();
316
317 private:
318  // Helper functions to create the map and find functions responsible for
319  // rendering well known types, keyed by type URL.
320  static hash_map<string, TypeRenderer>* renderers_;
321
322  // Variables for describing the structure of the input tree:
323  // master_type_: descriptor for the whole protobuf message.
324  const google::protobuf::Type& master_type_;
325
326  // The current element, variable for internal state processing.
327  google::protobuf::scoped_ptr<Item> current_;
328
329  // Reference to the options that control this class's behavior.
330  const ProtoStreamObjectWriter::Options options_;
331
332  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectWriter);
333};
334
335}  // namespace converter
336}  // namespace util
337}  // namespace protobuf
338
339}  // namespace google
340#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__
341