• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
OptionsOptions86     Options() : struct_integers_as_strings(false) {}
87 
88     // Default instance of Options with all options set to defaults.
DefaultsOptions89     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 
~Item()198     virtual ~Item() {}
199 
200     // These functions return true if the element type is corresponding to the
201     // type in function name.
IsMap()202     bool IsMap() { return item_type_ == MAP; }
IsAny()203     bool IsAny() { return item_type_ == ANY; }
204 
any()205     AnyWriter* any() const { return any_.get(); }
206 
parent()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 
is_placeholder()218     bool is_placeholder() const { return is_placeholder_; }
is_list()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