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_PROTO_WRITER_H__
32 #define GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_H__
33 
34 #include <deque>
35 #include <string>
36 #include <vector>
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/structured_objectwriter.h>
46 #include <google/protobuf/util/type_resolver.h>
47 #include <google/protobuf/stubs/bytestream.h>
48 #include <google/protobuf/stubs/hash.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 does not support special types like Struct or Map. However, since
72 // this class supports raw protobuf, it can be used to provide support for
73 // special types by inheriting from it or by wrapping it.
74 //
75 // It also supports streaming.
76 class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter {
77  public:
78 // Constructor. Does not take ownership of any parameter passed in.
79   ProtoWriter(TypeResolver* type_resolver, const google::protobuf::Type& type,
80               strings::ByteSink* output, ErrorListener* listener);
81   virtual ~ProtoWriter();
82 
83   // ObjectWriter methods.
84   virtual ProtoWriter* StartObject(StringPiece name);
85   virtual ProtoWriter* EndObject();
86   virtual ProtoWriter* StartList(StringPiece name);
87   virtual ProtoWriter* EndList();
RenderBool(StringPiece name,bool value)88   virtual ProtoWriter* RenderBool(StringPiece name, bool value) {
89     return RenderDataPiece(name, DataPiece(value));
90   }
RenderInt32(StringPiece name,int32 value)91   virtual ProtoWriter* RenderInt32(StringPiece name, int32 value) {
92     return RenderDataPiece(name, DataPiece(value));
93   }
RenderUint32(StringPiece name,uint32 value)94   virtual ProtoWriter* RenderUint32(StringPiece name, uint32 value) {
95     return RenderDataPiece(name, DataPiece(value));
96   }
RenderInt64(StringPiece name,int64 value)97   virtual ProtoWriter* RenderInt64(StringPiece name, int64 value) {
98     return RenderDataPiece(name, DataPiece(value));
99   }
RenderUint64(StringPiece name,uint64 value)100   virtual ProtoWriter* RenderUint64(StringPiece name, uint64 value) {
101     return RenderDataPiece(name, DataPiece(value));
102   }
RenderDouble(StringPiece name,double value)103   virtual ProtoWriter* RenderDouble(StringPiece name, double value) {
104     return RenderDataPiece(name, DataPiece(value));
105   }
RenderFloat(StringPiece name,float value)106   virtual ProtoWriter* RenderFloat(StringPiece name, float value) {
107     return RenderDataPiece(name, DataPiece(value));
108   }
RenderString(StringPiece name,StringPiece value)109   virtual ProtoWriter* RenderString(StringPiece name, StringPiece value) {
110     return RenderDataPiece(name,
111                            DataPiece(value, use_strict_base64_decoding()));
112   }
RenderBytes(StringPiece name,StringPiece value)113   virtual ProtoWriter* RenderBytes(StringPiece name, StringPiece value) {
114     return RenderDataPiece(
115         name, DataPiece(value, false, use_strict_base64_decoding()));
116   }
RenderNull(StringPiece name)117   virtual ProtoWriter* RenderNull(StringPiece name) {
118     return RenderDataPiece(name, DataPiece::NullData());
119   }
120 
121 
122   // Renders a DataPiece 'value' into a field whose wire type is determined
123   // from the given field 'name'.
124   virtual ProtoWriter* RenderDataPiece(StringPiece name,
125                                        const DataPiece& value);
126 
127   // Returns the location tracker to use for tracking locations for errors.
location()128   const LocationTrackerInterface& location() {
129     return element_ != NULL ? *element_ : *tracker_;
130   }
131 
132   // When true, we finished writing to output a complete message.
done()133   bool done() { return done_; }
134 
135   // Returns the proto stream object.
stream()136   google::protobuf::io::CodedOutputStream* stream() { return stream_.get(); }
137 
138   // Getters and mutators of invalid_depth_.
IncrementInvalidDepth()139   void IncrementInvalidDepth() { ++invalid_depth_; }
DecrementInvalidDepth()140   void DecrementInvalidDepth() { --invalid_depth_; }
invalid_depth()141   int invalid_depth() { return invalid_depth_; }
142 
listener()143   ErrorListener* listener() { return listener_; }
144 
typeinfo()145   const TypeInfo* typeinfo() { return typeinfo_; }
146 
set_ignore_unknown_fields(bool ignore_unknown_fields)147   void set_ignore_unknown_fields(bool ignore_unknown_fields) {
148     ignore_unknown_fields_ = ignore_unknown_fields;
149   }
150 
151  protected:
152   class LIBPROTOBUF_EXPORT ProtoElement : public BaseElement, public LocationTrackerInterface {
153    public:
154     // Constructor for the root element. No parent nor field.
155     ProtoElement(const TypeInfo* typeinfo, const google::protobuf::Type& type,
156                  ProtoWriter* enclosing);
157 
158     // Constructor for a field of an element.
159     ProtoElement(ProtoElement* parent, const google::protobuf::Field* field,
160                  const google::protobuf::Type& type, bool is_list);
161 
~ProtoElement()162     virtual ~ProtoElement() {}
163 
164     // Called just before the destructor for clean up:
165     //   - reports any missing required fields
166     //   - computes the space needed by the size field, and augment the
167     //     length of all parent messages by this additional space.
168     //   - releases and returns the parent pointer.
169     ProtoElement* pop();
170 
171     // Accessors
172     // parent_field() may be NULL if we are at root.
parent_field()173     const google::protobuf::Field* parent_field() const {
174       return parent_field_;
175     }
type()176     const google::protobuf::Type& type() const { return type_; }
177 
178     // Registers field for accounting required fields.
179     void RegisterField(const google::protobuf::Field* field);
180 
181     // To report location on error messages.
182     virtual string ToString() const;
183 
parent()184     virtual ProtoElement* parent() const {
185       return static_cast<ProtoElement*>(BaseElement::parent());
186     }
187 
188     // Returns true if the index is already taken by a preceding oneof input.
189     bool IsOneofIndexTaken(int32 index);
190 
191     // Marks the oneof 'index' as taken. Future inputs to this oneof will
192     // generate an error.
193     void TakeOneofIndex(int32 index);
194 
proto3()195     bool proto3() { return proto3_; }
196 
197    private:
198     // Used for access to variables of the enclosing instance of
199     // ProtoWriter.
200     ProtoWriter* ow_;
201 
202     // Describes the element as a field in the parent message.
203     // parent_field_ is NULL if and only if this element is the root element.
204     const google::protobuf::Field* parent_field_;
205 
206     // TypeInfo to lookup types.
207     const TypeInfo* typeinfo_;
208 
209     // Whether the type_ is proto3 or not.
210     bool proto3_;
211 
212     // Additional variables if this element is a message:
213     // (Root element is always a message).
214     // type_             : the type of this element.
215     // required_fields_  : set of required fields.
216     // size_index_       : index into ProtoWriter::size_insert_
217     //                     for later insertion of serialized message length.
218     const google::protobuf::Type& type_;
219     std::set<const google::protobuf::Field*> required_fields_;
220     const int size_index_;
221 
222     // Tracks position in repeated fields, needed for LocationTrackerInterface.
223     int array_index_;
224 
225     // Set of oneof indices already seen for the type_. Used to validate
226     // incoming messages so no more than one oneof is set.
227     std::vector<bool> oneof_indices_;
228 
229     GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoElement);
230   };
231 
232   // Container for inserting 'size' information at the 'pos' position.
233   struct SizeInfo {
234     const int pos;
235     int size;
236   };
237 
238   ProtoWriter(const TypeInfo* typeinfo, const google::protobuf::Type& type,
239               strings::ByteSink* output, ErrorListener* listener);
240 
element()241   virtual ProtoElement* element() { return element_.get(); }
242 
243   // Helper methods for calling ErrorListener. See error_listener.h.
244   void InvalidName(StringPiece unknown_name, StringPiece message);
245   void InvalidValue(StringPiece type_name, StringPiece value);
246   void MissingField(StringPiece missing_name);
247 
248   // Common code for BeginObject() and BeginList() that does invalid_depth_
249   // bookkeeping associated with name lookup.
250   const google::protobuf::Field* BeginNamed(StringPiece name, bool is_list);
251 
252   // Lookup the field in the current element. Looks in the base descriptor
253   // and in any extension. This will report an error if the field cannot be
254   // found when ignore_unknown_names_ is false or if multiple matching
255   // extensions are found.
256   const google::protobuf::Field* Lookup(StringPiece name);
257 
258   // Lookup the field type in the type descriptor. Returns NULL if the type
259   // is not known.
260   const google::protobuf::Type* LookupType(
261       const google::protobuf::Field* field);
262 
263   // Write serialized output to the final output ByteSink, inserting all
264   // the size information for nested messages that are missing from the
265   // intermediate Cord buffer.
266   void WriteRootMessage();
267 
268   // Helper method to write proto tags based on the given field.
269   void WriteTag(const google::protobuf::Field& field);
270 
271 
272   // Returns true if the field for type_ can be set as a oneof. If field is not
273   // a oneof type, this function does nothing and returns true.
274   // If another field for this oneof is already set, this function returns
275   // false. It also calls the appropriate error callback.
276   // unnormalized_name is used for error string.
277   bool ValidOneof(const google::protobuf::Field& field,
278                   StringPiece unnormalized_name);
279 
280   // Returns true if the field is repeated.
281   bool IsRepeated(const google::protobuf::Field& field);
282 
283   // Starts an object given the field and the enclosing type.
284   ProtoWriter* StartObjectField(const google::protobuf::Field& field,
285                                 const google::protobuf::Type& type);
286 
287   // Starts a list given the field and the enclosing type.
288   ProtoWriter* StartListField(const google::protobuf::Field& field,
289                               const google::protobuf::Type& type);
290 
291   // Renders a primitve field given the field and the enclosing type.
292   ProtoWriter* RenderPrimitiveField(const google::protobuf::Field& field,
293                                     const google::protobuf::Type& type,
294                                     const DataPiece& value);
295 
296  private:
297   // Variables for describing the structure of the input tree:
298   // master_type_: descriptor for the whole protobuf message.
299   // typeinfo_ : the TypeInfo object to lookup types.
300   const google::protobuf::Type& master_type_;
301   const TypeInfo* typeinfo_;
302   // Whether we own the typeinfo_ object.
303   bool own_typeinfo_;
304 
305   // Indicates whether we finished writing root message completely.
306   bool done_;
307 
308   // If true, don't report unknown field names to the listener.
309   bool ignore_unknown_fields_;
310 
311   // Variable for internal state processing:
312   // element_    : the current element.
313   // size_insert_: sizes of nested messages.
314   //               pos  - position to insert the size field.
315   //               size - size value to be inserted.
316   google::protobuf::scoped_ptr<ProtoElement> element_;
317   std::deque<SizeInfo> size_insert_;
318 
319   // Variables for output generation:
320   // output_  : pointer to an external ByteSink for final user-visible output.
321   // buffer_  : buffer holding partial message before being ready for output_.
322   // adapter_ : internal adapter between CodedOutputStream and buffer_.
323   // stream_  : wrapper for writing tags and other encodings in wire format.
324   strings::ByteSink* output_;
325   string buffer_;
326   google::protobuf::io::StringOutputStream adapter_;
327   google::protobuf::scoped_ptr<google::protobuf::io::CodedOutputStream> stream_;
328 
329   // Variables for error tracking and reporting:
330   // listener_     : a place to report any errors found.
331   // invalid_depth_: number of enclosing invalid nested messages.
332   // tracker_      : the root location tracker interface.
333   ErrorListener* listener_;
334   int invalid_depth_;
335   google::protobuf::scoped_ptr<LocationTrackerInterface> tracker_;
336 
337   GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoWriter);
338 };
339 
340 }  // namespace converter
341 }  // namespace util
342 }  // namespace protobuf
343 
344 }  // namespace google
345 #endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_H__
346