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 
50 namespace google {
51 namespace protobuf {
52 namespace io {
53 class CodedOutputStream;
54 }  // namespace io
55 }  // namespace protobuf
56 
57 
58 namespace protobuf {
59 class Type;
60 class Field;
61 }  // namespace protobuf
62 
63 
64 namespace protobuf {
65 namespace util {
66 namespace converter {
67 
68 class 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.
75 class 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     // Not treat unknown fields as an error. If there is an unknown fields,
87     // just ignore it and continue to process the rest.
88     bool ignore_unknown_fields;
89 
OptionsOptions90     Options()
91         : struct_integers_as_strings(false), ignore_unknown_fields(false) {}
92 
93     // Default instance of Options with all options set to defaults.
DefaultsOptions94     static const Options& Defaults() {
95       static Options defaults;
96       return defaults;
97     }
98   };
99 
100 // Constructor. Does not take ownership of any parameter passed in.
101   ProtoStreamObjectWriter(TypeResolver* type_resolver,
102                           const google::protobuf::Type& type,
103                           strings::ByteSink* output, ErrorListener* listener,
104                           const ProtoStreamObjectWriter::Options& options =
105                               ProtoStreamObjectWriter::Options::Defaults());
106   virtual ~ProtoStreamObjectWriter();
107 
108   // ObjectWriter methods.
109   virtual ProtoStreamObjectWriter* StartObject(StringPiece name);
110   virtual ProtoStreamObjectWriter* EndObject();
111   virtual ProtoStreamObjectWriter* StartList(StringPiece name);
112   virtual ProtoStreamObjectWriter* EndList();
113 
114   // Renders a DataPiece 'value' into a field whose wire type is determined
115   // from the given field 'name'.
116   virtual ProtoStreamObjectWriter* RenderDataPiece(StringPiece name,
117                                                    const DataPiece& value);
118 
119  protected:
120   // Function that renders a well known type with modified behavior.
121   typedef util::Status (*TypeRenderer)(ProtoStreamObjectWriter*,
122                                          const DataPiece&);
123 
124   // Handles writing Anys out using nested object writers and the like.
125   class LIBPROTOBUF_EXPORT AnyWriter {
126    public:
127     explicit AnyWriter(ProtoStreamObjectWriter* parent);
128     ~AnyWriter();
129 
130     // Passes a StartObject call through to the Any writer.
131     void StartObject(StringPiece name);
132 
133     // Passes an EndObject call through to the Any. Returns true if the any
134     // handled the EndObject call, false if the Any is now all done and is no
135     // longer needed.
136     bool EndObject();
137 
138     // Passes a StartList call through to the Any writer.
139     void StartList(StringPiece name);
140 
141     // Passes an EndList call through to the Any writer.
142     void EndList();
143 
144     // Renders a data piece on the any.
145     void RenderDataPiece(StringPiece name, const DataPiece& value);
146 
147    private:
148     // Handles starting up the any once we have a type.
149     void StartAny(const DataPiece& value);
150 
151     // Writes the Any out to the parent writer in its serialized form.
152     void WriteAny();
153 
154     // The parent of this writer, needed for various bits such as type info and
155     // the listeners.
156     ProtoStreamObjectWriter* parent_;
157 
158     // The nested object writer, used to write events.
159     google::protobuf::scoped_ptr<ProtoStreamObjectWriter> ow_;
160 
161     // The type_url_ that this Any represents.
162     string type_url_;
163 
164     // Whether this any is invalid. This allows us to only report an invalid
165     // Any message a single time rather than every time we get a nested field.
166     bool invalid_;
167 
168     // The output data and wrapping ByteSink.
169     string data_;
170     strings::StringByteSink output_;
171 
172     // The depth within the Any, so we can track when we're done.
173     int depth_;
174 
175     // True if the type is a well-known type. Well-known types in Any
176     // has a special formating:
177     // {
178     //   "@type": "type.googleapis.com/google.protobuf.XXX",
179     //   "value": <JSON representation of the type>,
180     // }
181     bool is_well_known_type_;
182     TypeRenderer* well_known_type_render_;
183   };
184 
185   // Represents an item in a stack of items used to keep state between
186   // ObjectWrier events.
187   class LIBPROTOBUF_EXPORT Item : public BaseElement {
188    public:
189     // Indicates the type of item.
190     enum ItemType {
191       MESSAGE,  // Simple message
192       MAP,      // Proto3 map type
193       ANY,      // Proto3 Any type
194     };
195 
196     // Constructor for the root item.
197     Item(ProtoStreamObjectWriter* enclosing, ItemType item_type,
198          bool is_placeholder, bool is_list);
199 
200     // Constructor for a field of a message.
201     Item(Item* parent, ItemType item_type, bool is_placeholder, bool is_list);
202 
~Item()203     virtual ~Item() {}
204 
205     // These functions return true if the element type is corresponding to the
206     // type in function name.
IsMap()207     bool IsMap() { return item_type_ == MAP; }
IsAny()208     bool IsAny() { return item_type_ == ANY; }
209 
any()210     AnyWriter* any() const { return any_.get(); }
211 
parent()212     virtual Item* parent() const {
213       return static_cast<Item*>(BaseElement::parent());
214     }
215 
216     // Inserts map key into hash set if and only if the key did NOT already
217     // exist in hash set.
218     // The hash set (map_keys_) is ONLY used to keep track of map keys.
219     // Return true if insert successfully; returns false if the map key was
220     // already present.
221     bool InsertMapKeyIfNotPresent(StringPiece map_key);
222 
is_placeholder()223     bool is_placeholder() const { return is_placeholder_; }
is_list()224     bool is_list() const { return is_list_; }
225 
226    private:
227     // Used for access to variables of the enclosing instance of
228     // ProtoStreamObjectWriter.
229     ProtoStreamObjectWriter* ow_;
230 
231     // A writer for Any objects, handles all Any-related nonsense.
232     google::protobuf::scoped_ptr<AnyWriter> any_;
233 
234     // The type of this element, see enum for permissible types.
235     ItemType item_type_;
236 
237     // Set of map keys already seen for the type_. Used to validate incoming
238     // messages so no map key appears more than once.
239     google::protobuf::scoped_ptr<hash_set<string> > map_keys_;
240 
241     // Conveys whether this Item is a placeholder or not. Placeholder items are
242     // pushed to stack to account for special types.
243     bool is_placeholder_;
244 
245     // Conveys whether this Item is a list or not. This is used to send
246     // StartList or EndList calls to underlying ObjectWriter.
247     bool is_list_;
248 
249     GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Item);
250   };
251 
252   ProtoStreamObjectWriter(const TypeInfo* typeinfo,
253                           const google::protobuf::Type& type,
254                           strings::ByteSink* output, ErrorListener* listener);
255 
256   // Returns true if the field is a map.
257   inline bool IsMap(const google::protobuf::Field& field);
258 
259   // Returns true if the field is an any.
260   inline bool IsAny(const google::protobuf::Field& field);
261 
262   // Returns true if the field is google.protobuf.Struct.
263   inline bool IsStruct(const google::protobuf::Field& field);
264 
265   // Returns true if the field is google.protobuf.Value.
266   inline bool IsStructValue(const google::protobuf::Field& field);
267 
268   // Returns true if the field is google.protobuf.ListValue.
269   inline bool IsStructListValue(const google::protobuf::Field& field);
270 
271   // Renders google.protobuf.Value in struct.proto. It picks the right oneof
272   // type based on value's type.
273   static util::Status RenderStructValue(ProtoStreamObjectWriter* ow,
274                                           const DataPiece& value);
275 
276   // Renders google.protobuf.Timestamp value.
277   static util::Status RenderTimestamp(ProtoStreamObjectWriter* ow,
278                                         const DataPiece& value);
279 
280   // Renders google.protobuf.FieldMask value.
281   static util::Status RenderFieldMask(ProtoStreamObjectWriter* ow,
282                                         const DataPiece& value);
283 
284   // Renders google.protobuf.Duration value.
285   static util::Status RenderDuration(ProtoStreamObjectWriter* ow,
286                                        const DataPiece& value);
287 
288   // Renders wrapper message types for primitive types in
289   // google/protobuf/wrappers.proto.
290   static util::Status RenderWrapperType(ProtoStreamObjectWriter* ow,
291                                           const DataPiece& value);
292 
293   static void InitRendererMap();
294   static void DeleteRendererMap();
295   static TypeRenderer* FindTypeRenderer(const string& type_url);
296 
297   // Returns true if the map key for type_ is not duplicated key.
298   // If map key is duplicated key, this function returns false.
299   // Note that caller should make sure that the current proto element (current_)
300   // is of element type MAP or STRUCT_MAP.
301   // It also calls the appropriate error callback and unnormalzied_name is used
302   // for error string.
303   bool ValidMapKey(StringPiece unnormalized_name);
304 
305   // Pushes an item on to the stack. Also calls either StartObject or StartList
306   // on the underlying ObjectWriter depending on whether is_list is false or
307   // not.
308   // is_placeholder conveys whether the item is a placeholder item or not.
309   // Placeholder items are pushed when adding auxillary types' StartObject or
310   // StartList calls.
311   void Push(StringPiece name, Item::ItemType item_type, bool is_placeholder,
312             bool is_list);
313 
314   // Pops items from the stack. All placeholder items are popped until a
315   // non-placeholder item is found.
316   void Pop();
317 
318   // Pops one element from the stack. Calls EndObject() or EndList() on the
319   // underlying ObjectWriter depending on the value of is_list_.
320   void PopOneElement();
321 
322  private:
323   // Helper functions to create the map and find functions responsible for
324   // rendering well known types, keyed by type URL.
325   static hash_map<string, TypeRenderer>* renderers_;
326 
327   // Variables for describing the structure of the input tree:
328   // master_type_: descriptor for the whole protobuf message.
329   const google::protobuf::Type& master_type_;
330 
331   // The current element, variable for internal state processing.
332   google::protobuf::scoped_ptr<Item> current_;
333 
334   // Reference to the options that control this class's behavior.
335   const ProtoStreamObjectWriter::Options options_;
336 
337   GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectWriter);
338 };
339 
340 }  // namespace converter
341 }  // namespace util
342 }  // namespace protobuf
343 
344 }  // namespace google
345 #endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__
346