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