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