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