• 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 #include <google/protobuf/util/internal/proto_writer.h>
32 
33 #include <functional>
34 #include <stack>
35 
36 #include <google/protobuf/stubs/once.h>
37 #include <google/protobuf/wire_format_lite.h>
38 #include <google/protobuf/util/internal/field_mask_utility.h>
39 #include <google/protobuf/util/internal/object_location_tracker.h>
40 #include <google/protobuf/util/internal/constants.h>
41 #include <google/protobuf/util/internal/utility.h>
42 #include <google/protobuf/stubs/strutil.h>
43 #include <google/protobuf/stubs/time.h>
44 #include <google/protobuf/stubs/map_util.h>
45 #include <google/protobuf/stubs/statusor.h>
46 
47 
48 #include <google/protobuf/port_def.inc>
49 
50 namespace google {
51 namespace protobuf {
52 namespace util {
53 namespace converter {
54 
55 using io::CodedOutputStream;
56 using ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite;
57 using util::Status;
58 using util::StatusOr;
59 using util::error::INVALID_ARGUMENT;
60 
61 
ProtoWriter(TypeResolver * type_resolver,const google::protobuf::Type & type,strings::ByteSink * output,ErrorListener * listener)62 ProtoWriter::ProtoWriter(TypeResolver* type_resolver,
63                          const google::protobuf::Type& type,
64                          strings::ByteSink* output, ErrorListener* listener)
65     : master_type_(type),
66       typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
67       own_typeinfo_(true),
68       done_(false),
69       ignore_unknown_fields_(false),
70       ignore_unknown_enum_values_(false),
71       use_lower_camel_for_enums_(false),
72       case_insensitive_enum_parsing_(true),
73       element_(nullptr),
74       size_insert_(),
75       output_(output),
76       buffer_(),
77       adapter_(&buffer_),
78       stream_(new CodedOutputStream(&adapter_)),
79       listener_(listener),
80       invalid_depth_(0),
81       tracker_(new ObjectLocationTracker()) {}
82 
ProtoWriter(const TypeInfo * typeinfo,const google::protobuf::Type & type,strings::ByteSink * output,ErrorListener * listener)83 ProtoWriter::ProtoWriter(const TypeInfo* typeinfo,
84                          const google::protobuf::Type& type,
85                          strings::ByteSink* output, ErrorListener* listener)
86     : master_type_(type),
87       typeinfo_(typeinfo),
88       own_typeinfo_(false),
89       done_(false),
90       ignore_unknown_fields_(false),
91       ignore_unknown_enum_values_(false),
92       use_lower_camel_for_enums_(false),
93       case_insensitive_enum_parsing_(true),
94       element_(nullptr),
95       size_insert_(),
96       output_(output),
97       buffer_(),
98       adapter_(&buffer_),
99       stream_(new CodedOutputStream(&adapter_)),
100       listener_(listener),
101       invalid_depth_(0),
102       tracker_(new ObjectLocationTracker()) {}
103 
~ProtoWriter()104 ProtoWriter::~ProtoWriter() {
105   if (own_typeinfo_) {
106     delete typeinfo_;
107   }
108   if (element_ == nullptr) return;
109   // Cleanup explicitly in order to avoid destructor stack overflow when input
110   // is deeply nested.
111   // Cast to BaseElement to avoid doing additional checks (like missing fields)
112   // during pop().
113   std::unique_ptr<BaseElement> element(
114       static_cast<BaseElement*>(element_.get())->pop<BaseElement>());
115   while (element != nullptr) {
116     element.reset(element->pop<BaseElement>());
117   }
118 }
119 
120 namespace {
121 
122 // Writes an INT32 field, including tag to the stream.
WriteInt32(int field_number,const DataPiece & data,CodedOutputStream * stream)123 inline Status WriteInt32(int field_number, const DataPiece& data,
124                          CodedOutputStream* stream) {
125   StatusOr<int32> i32 = data.ToInt32();
126   if (i32.ok()) {
127     WireFormatLite::WriteInt32(field_number, i32.value(), stream);
128   }
129   return i32.status();
130 }
131 
132 // writes an SFIXED32 field, including tag, to the stream.
WriteSFixed32(int field_number,const DataPiece & data,CodedOutputStream * stream)133 inline Status WriteSFixed32(int field_number, const DataPiece& data,
134                             CodedOutputStream* stream) {
135   StatusOr<int32> i32 = data.ToInt32();
136   if (i32.ok()) {
137     WireFormatLite::WriteSFixed32(field_number, i32.value(), stream);
138   }
139   return i32.status();
140 }
141 
142 // Writes an SINT32 field, including tag, to the stream.
WriteSInt32(int field_number,const DataPiece & data,CodedOutputStream * stream)143 inline Status WriteSInt32(int field_number, const DataPiece& data,
144                           CodedOutputStream* stream) {
145   StatusOr<int32> i32 = data.ToInt32();
146   if (i32.ok()) {
147     WireFormatLite::WriteSInt32(field_number, i32.value(), stream);
148   }
149   return i32.status();
150 }
151 
152 // Writes a FIXED32 field, including tag, to the stream.
WriteFixed32(int field_number,const DataPiece & data,CodedOutputStream * stream)153 inline Status WriteFixed32(int field_number, const DataPiece& data,
154                            CodedOutputStream* stream) {
155   StatusOr<uint32> u32 = data.ToUint32();
156   if (u32.ok()) {
157     WireFormatLite::WriteFixed32(field_number, u32.value(), stream);
158   }
159   return u32.status();
160 }
161 
162 // Writes a UINT32 field, including tag, to the stream.
WriteUInt32(int field_number,const DataPiece & data,CodedOutputStream * stream)163 inline Status WriteUInt32(int field_number, const DataPiece& data,
164                           CodedOutputStream* stream) {
165   StatusOr<uint32> u32 = data.ToUint32();
166   if (u32.ok()) {
167     WireFormatLite::WriteUInt32(field_number, u32.value(), stream);
168   }
169   return u32.status();
170 }
171 
172 // Writes an INT64 field, including tag, to the stream.
WriteInt64(int field_number,const DataPiece & data,CodedOutputStream * stream)173 inline Status WriteInt64(int field_number, const DataPiece& data,
174                          CodedOutputStream* stream) {
175   StatusOr<int64> i64 = data.ToInt64();
176   if (i64.ok()) {
177     WireFormatLite::WriteInt64(field_number, i64.value(), stream);
178   }
179   return i64.status();
180 }
181 
182 // Writes an SFIXED64 field, including tag, to the stream.
WriteSFixed64(int field_number,const DataPiece & data,CodedOutputStream * stream)183 inline Status WriteSFixed64(int field_number, const DataPiece& data,
184                             CodedOutputStream* stream) {
185   StatusOr<int64> i64 = data.ToInt64();
186   if (i64.ok()) {
187     WireFormatLite::WriteSFixed64(field_number, i64.value(), stream);
188   }
189   return i64.status();
190 }
191 
192 // Writes an SINT64 field, including tag, to the stream.
WriteSInt64(int field_number,const DataPiece & data,CodedOutputStream * stream)193 inline Status WriteSInt64(int field_number, const DataPiece& data,
194                           CodedOutputStream* stream) {
195   StatusOr<int64> i64 = data.ToInt64();
196   if (i64.ok()) {
197     WireFormatLite::WriteSInt64(field_number, i64.value(), stream);
198   }
199   return i64.status();
200 }
201 
202 // Writes a FIXED64 field, including tag, to the stream.
WriteFixed64(int field_number,const DataPiece & data,CodedOutputStream * stream)203 inline Status WriteFixed64(int field_number, const DataPiece& data,
204                            CodedOutputStream* stream) {
205   StatusOr<uint64> u64 = data.ToUint64();
206   if (u64.ok()) {
207     WireFormatLite::WriteFixed64(field_number, u64.value(), stream);
208   }
209   return u64.status();
210 }
211 
212 // Writes a UINT64 field, including tag, to the stream.
WriteUInt64(int field_number,const DataPiece & data,CodedOutputStream * stream)213 inline Status WriteUInt64(int field_number, const DataPiece& data,
214                           CodedOutputStream* stream) {
215   StatusOr<uint64> u64 = data.ToUint64();
216   if (u64.ok()) {
217     WireFormatLite::WriteUInt64(field_number, u64.value(), stream);
218   }
219   return u64.status();
220 }
221 
222 // Writes a DOUBLE field, including tag, to the stream.
WriteDouble(int field_number,const DataPiece & data,CodedOutputStream * stream)223 inline Status WriteDouble(int field_number, const DataPiece& data,
224                           CodedOutputStream* stream) {
225   StatusOr<double> d = data.ToDouble();
226   if (d.ok()) {
227     WireFormatLite::WriteDouble(field_number, d.value(), stream);
228   }
229   return d.status();
230 }
231 
232 // Writes a FLOAT field, including tag, to the stream.
WriteFloat(int field_number,const DataPiece & data,CodedOutputStream * stream)233 inline Status WriteFloat(int field_number, const DataPiece& data,
234                          CodedOutputStream* stream) {
235   StatusOr<float> f = data.ToFloat();
236   if (f.ok()) {
237     WireFormatLite::WriteFloat(field_number, f.value(), stream);
238   }
239   return f.status();
240 }
241 
242 // Writes a BOOL field, including tag, to the stream.
WriteBool(int field_number,const DataPiece & data,CodedOutputStream * stream)243 inline Status WriteBool(int field_number, const DataPiece& data,
244                         CodedOutputStream* stream) {
245   StatusOr<bool> b = data.ToBool();
246   if (b.ok()) {
247     WireFormatLite::WriteBool(field_number, b.value(), stream);
248   }
249   return b.status();
250 }
251 
252 // Writes a BYTES field, including tag, to the stream.
WriteBytes(int field_number,const DataPiece & data,CodedOutputStream * stream)253 inline Status WriteBytes(int field_number, const DataPiece& data,
254                          CodedOutputStream* stream) {
255   StatusOr<std::string> c = data.ToBytes();
256   if (c.ok()) {
257     WireFormatLite::WriteBytes(field_number, c.ValueOrDie(), stream);
258   }
259   return c.status();
260 }
261 
262 // Writes a STRING field, including tag, to the stream.
WriteString(int field_number,const DataPiece & data,CodedOutputStream * stream)263 inline Status WriteString(int field_number, const DataPiece& data,
264                           CodedOutputStream* stream) {
265   StatusOr<std::string> s = data.ToString();
266   if (s.ok()) {
267     WireFormatLite::WriteString(field_number, s.value(), stream);
268   }
269   return s.status();
270 }
271 
272 // Given a google::protobuf::Type, returns the set of all required fields.
GetRequiredFields(const google::protobuf::Type & type)273 std::set<const google::protobuf::Field*> GetRequiredFields(
274     const google::protobuf::Type& type) {
275   std::set<const google::protobuf::Field*> required;
276   for (int i = 0; i < type.fields_size(); i++) {
277     const google::protobuf::Field& field = type.fields(i);
278     if (field.cardinality() == google::protobuf::Field::CARDINALITY_REQUIRED) {
279       required.insert(&field);
280     }
281   }
282   return required;
283 }
284 
285 }  // namespace
286 
ProtoElement(const TypeInfo * typeinfo,const google::protobuf::Type & type,ProtoWriter * enclosing)287 ProtoWriter::ProtoElement::ProtoElement(const TypeInfo* typeinfo,
288                                         const google::protobuf::Type& type,
289                                         ProtoWriter* enclosing)
290     : BaseElement(nullptr),
291       ow_(enclosing),
292       parent_field_(nullptr),
293       typeinfo_(typeinfo),
294       proto3_(type.syntax() == google::protobuf::SYNTAX_PROTO3),
295       type_(type),
296       size_index_(-1),
297       array_index_(-1),
298       // oneof_indices_ values are 1-indexed (0 means not present).
299       oneof_indices_(type.oneofs_size() + 1) {
300   if (!proto3_) {
301     required_fields_ = GetRequiredFields(type_);
302   }
303 }
304 
ProtoElement(ProtoWriter::ProtoElement * parent,const google::protobuf::Field * field,const google::protobuf::Type & type,bool is_list)305 ProtoWriter::ProtoElement::ProtoElement(ProtoWriter::ProtoElement* parent,
306                                         const google::protobuf::Field* field,
307                                         const google::protobuf::Type& type,
308                                         bool is_list)
309     : BaseElement(parent),
310       ow_(this->parent()->ow_),
311       parent_field_(field),
312       typeinfo_(this->parent()->typeinfo_),
313       proto3_(type.syntax() == google::protobuf::SYNTAX_PROTO3),
314       type_(type),
315       size_index_(!is_list &&
316                           field->kind() == google::protobuf::Field::TYPE_MESSAGE
317                       ? ow_->size_insert_.size()
318                       : -1),
319       array_index_(is_list ? 0 : -1),
320       // oneof_indices_ values are 1-indexed (0 means not present).
321       oneof_indices_(type_.oneofs_size() + 1) {
322   if (!is_list) {
323     if (ow_->IsRepeated(*field)) {
324       // Update array_index_ if it is an explicit list.
325       if (this->parent()->array_index_ >= 0) this->parent()->array_index_++;
326     } else if (!proto3_) {
327       // For required fields tracking.
328       this->parent()->RegisterField(field);
329     }
330 
331     if (field->kind() == google::protobuf::Field::TYPE_MESSAGE) {
332       if (!proto3_) {
333         required_fields_ = GetRequiredFields(type_);
334       }
335       int start_pos = ow_->stream_->ByteCount();
336       // length of serialized message is the final buffer position minus
337       // starting buffer position, plus length adjustments for size fields
338       // of any nested messages. We start with -start_pos here, so we only
339       // need to add the final buffer position to it at the end.
340       SizeInfo info = {start_pos, -start_pos};
341       ow_->size_insert_.push_back(info);
342     }
343   }
344 }
345 
pop()346 ProtoWriter::ProtoElement* ProtoWriter::ProtoElement::pop() {
347   if (!proto3_) {
348     // Calls the registered error listener for any required field(s) not yet
349     // seen.
350     for (std::set<const google::protobuf::Field*>::iterator it =
351              required_fields_.begin();
352          it != required_fields_.end(); ++it) {
353       ow_->MissingField((*it)->name());
354     }
355   }
356   // Computes the total number of proto bytes used by a message, also adjusts
357   // the size of all parent messages by the length of this size field.
358   // If size_index_ < 0, this is not a message, so no size field is added.
359   if (size_index_ >= 0) {
360     // Add the final buffer position to compute the total length of this
361     // serialized message. The stored value (before this addition) already
362     // contains the total length of the size fields of all nested messages
363     // minus the initial buffer position.
364     ow_->size_insert_[size_index_].size += ow_->stream_->ByteCount();
365     // Calculate the length required to serialize the size field of the
366     // message, and propagate this additional size information upward to
367     // all enclosing messages.
368     int size = ow_->size_insert_[size_index_].size;
369     int length = CodedOutputStream::VarintSize32(size);
370     for (ProtoElement* e = parent(); e != nullptr; e = e->parent()) {
371       // Only nested messages have size field, lists do not have size field.
372       if (e->size_index_ >= 0) {
373         ow_->size_insert_[e->size_index_].size += length;
374       }
375     }
376   }
377   return BaseElement::pop<ProtoElement>();
378 }
379 
RegisterField(const google::protobuf::Field * field)380 void ProtoWriter::ProtoElement::RegisterField(
381     const google::protobuf::Field* field) {
382   if (!required_fields_.empty() &&
383       field->cardinality() == google::protobuf::Field::CARDINALITY_REQUIRED) {
384     required_fields_.erase(field);
385   }
386 }
387 
ToString() const388 std::string ProtoWriter::ProtoElement::ToString() const {
389   std::string loc = "";
390 
391   // first populate a stack with the nodes since we need to process them
392   // from root to leaf when generating the string location
393   const ProtoWriter::ProtoElement* now = this;
394   std::stack<const ProtoWriter::ProtoElement*> element_stack;
395   while (now->parent() != nullptr) {
396     element_stack.push(now);
397     now = now->parent();
398   }
399 
400   // now pop each node from the stack and append to the location string
401   while (!element_stack.empty()) {
402     now = element_stack.top();
403     element_stack.pop();
404 
405     if (!ow_->IsRepeated(*(now->parent_field_)) ||
406         now->parent()->parent_field_ != now->parent_field_) {
407       std::string name = now->parent_field_->name();
408       int i = 0;
409       while (i < name.size() &&
410              (ascii_isalnum(name[i]) || name[i] == '_'))
411         ++i;
412       if (i > 0 && i == name.size()) {  // safe field name
413         if (loc.empty()) {
414           loc = name;
415         } else {
416           StrAppend(&loc, ".", name);
417         }
418       } else {
419         StrAppend(&loc, "[\"", CEscape(name), "\"]");
420       }
421     }
422 
423     int array_index_now = now->array_index_;
424     if (ow_->IsRepeated(*(now->parent_field_)) && array_index_now > 0) {
425       StrAppend(&loc, "[", array_index_now - 1, "]");
426     }
427   }
428 
429   return loc;
430 }
431 
IsOneofIndexTaken(int32 index)432 bool ProtoWriter::ProtoElement::IsOneofIndexTaken(int32 index) {
433   return oneof_indices_[index];
434 }
435 
TakeOneofIndex(int32 index)436 void ProtoWriter::ProtoElement::TakeOneofIndex(int32 index) {
437   oneof_indices_[index] = true;
438 }
439 
InvalidName(StringPiece unknown_name,StringPiece message)440 void ProtoWriter::InvalidName(StringPiece unknown_name,
441                               StringPiece message) {
442   listener_->InvalidName(location(), unknown_name, message);
443 }
444 
InvalidValue(StringPiece type_name,StringPiece value)445 void ProtoWriter::InvalidValue(StringPiece type_name,
446                                StringPiece value) {
447   listener_->InvalidValue(location(), type_name, value);
448 }
449 
MissingField(StringPiece missing_name)450 void ProtoWriter::MissingField(StringPiece missing_name) {
451   listener_->MissingField(location(), missing_name);
452 }
453 
StartObject(StringPiece name)454 ProtoWriter* ProtoWriter::StartObject(
455     StringPiece name) {
456   // Starting the root message. Create the root ProtoElement and return.
457   if (element_ == nullptr) {
458     if (!name.empty()) {
459       InvalidName(name, "Root element should not be named.");
460     }
461     element_.reset(new ProtoElement(typeinfo_, master_type_, this));
462     return this;
463   }
464 
465   const google::protobuf::Field* field = BeginNamed(name, false);
466 
467   if (field == nullptr) return this;
468 
469   // Check to see if this field is a oneof and that no oneof in that group has
470   // already been set.
471   if (!ValidOneof(*field, name)) {
472     ++invalid_depth_;
473     return this;
474   }
475 
476   const google::protobuf::Type* type = LookupType(field);
477   if (type == nullptr) {
478     ++invalid_depth_;
479     InvalidName(name, StrCat("Missing descriptor for field: ",
480                                    field->type_url()));
481     return this;
482   }
483 
484   return StartObjectField(*field, *type);
485 }
486 
487 
EndObject()488 ProtoWriter* ProtoWriter::EndObject() {
489   if (invalid_depth_ > 0) {
490     --invalid_depth_;
491     return this;
492   }
493 
494   if (element_ != nullptr) {
495     element_.reset(element_->pop());
496   }
497 
498 
499   // If ending the root element,
500   // then serialize the full message with calculated sizes.
501   if (element_ == nullptr) {
502     WriteRootMessage();
503   }
504   return this;
505 }
506 
StartList(StringPiece name)507 ProtoWriter* ProtoWriter::StartList(
508     StringPiece name) {
509 
510   const google::protobuf::Field* field = BeginNamed(name, true);
511 
512   if (field == nullptr) return this;
513 
514   if (!ValidOneof(*field, name)) {
515     ++invalid_depth_;
516     return this;
517   }
518 
519   const google::protobuf::Type* type = LookupType(field);
520   if (type == nullptr) {
521     ++invalid_depth_;
522     InvalidName(name, StrCat("Missing descriptor for field: ",
523                                    field->type_url()));
524     return this;
525   }
526 
527   return StartListField(*field, *type);
528 }
529 
530 
EndList()531 ProtoWriter* ProtoWriter::EndList() {
532   if (invalid_depth_ > 0) {
533     --invalid_depth_;
534   } else if (element_ != nullptr) {
535     element_.reset(element_->pop());
536   }
537   return this;
538 }
539 
RenderDataPiece(StringPiece name,const DataPiece & data)540 ProtoWriter* ProtoWriter::RenderDataPiece(
541     StringPiece name, const DataPiece& data) {
542   Status status;
543   if (invalid_depth_ > 0) return this;
544 
545   const google::protobuf::Field* field = Lookup(name);
546 
547   if (field == nullptr) return this;
548 
549   if (!ValidOneof(*field, name)) return this;
550 
551   const google::protobuf::Type* type = LookupType(field);
552   if (type == nullptr) {
553     InvalidName(name, StrCat("Missing descriptor for field: ",
554                                    field->type_url()));
555     return this;
556   }
557 
558   return RenderPrimitiveField(*field, *type, data);
559 }
560 
ValidOneof(const google::protobuf::Field & field,StringPiece unnormalized_name)561 bool ProtoWriter::ValidOneof(const google::protobuf::Field& field,
562                              StringPiece unnormalized_name) {
563   if (element_ == nullptr) return true;
564 
565   if (field.oneof_index() > 0) {
566     if (element_->IsOneofIndexTaken(field.oneof_index())) {
567       InvalidValue(
568           "oneof",
569           StrCat(
570               "oneof field '", element_->type().oneofs(field.oneof_index() - 1),
571               "' is already set. Cannot set '", unnormalized_name, "'"));
572       return false;
573     }
574     element_->TakeOneofIndex(field.oneof_index());
575   }
576   return true;
577 }
578 
IsRepeated(const google::protobuf::Field & field)579 bool ProtoWriter::IsRepeated(const google::protobuf::Field& field) {
580   return field.cardinality() == google::protobuf::Field::CARDINALITY_REPEATED;
581 }
582 
StartObjectField(const google::protobuf::Field & field,const google::protobuf::Type & type)583 ProtoWriter* ProtoWriter::StartObjectField(const google::protobuf::Field& field,
584                                            const google::protobuf::Type& type) {
585     WriteTag(field);
586   element_.reset(new ProtoElement(element_.release(), &field, type, false));
587   return this;
588 }
589 
StartListField(const google::protobuf::Field & field,const google::protobuf::Type & type)590 ProtoWriter* ProtoWriter::StartListField(const google::protobuf::Field& field,
591                                          const google::protobuf::Type& type) {
592   element_.reset(new ProtoElement(element_.release(), &field, type, true));
593   return this;
594 }
595 
WriteEnum(int field_number,const DataPiece & data,const google::protobuf::Enum * enum_type,CodedOutputStream * stream,bool use_lower_camel_for_enums,bool case_insensitive_enum_parsing,bool ignore_unknown_values)596 Status ProtoWriter::WriteEnum(int field_number, const DataPiece& data,
597                               const google::protobuf::Enum* enum_type,
598                               CodedOutputStream* stream,
599                               bool use_lower_camel_for_enums,
600                               bool case_insensitive_enum_parsing,
601                               bool ignore_unknown_values) {
602   bool is_unknown_enum_value = false;
603   StatusOr<int> e = data.ToEnum(enum_type, use_lower_camel_for_enums,
604                                 case_insensitive_enum_parsing,
605                                 ignore_unknown_values, &is_unknown_enum_value);
606   if (e.ok() && !is_unknown_enum_value) {
607     WireFormatLite::WriteEnum(field_number, e.value(), stream);
608   }
609   return e.status();
610 }
611 
RenderPrimitiveField(const google::protobuf::Field & field,const google::protobuf::Type & type,const DataPiece & data)612 ProtoWriter* ProtoWriter::RenderPrimitiveField(
613     const google::protobuf::Field& field, const google::protobuf::Type& type,
614     const DataPiece& data) {
615   Status status;
616 
617   // Pushing a ProtoElement and then pop it off at the end for 2 purposes:
618   // error location reporting and required field accounting.
619   //
620   // For proto3, since there is no required field tracking, we only need to push
621   // ProtoElement for error cases.
622   if (!element_->proto3()) {
623     element_.reset(new ProtoElement(element_.release(), &field, type, false));
624   }
625 
626   if (field.kind() == google::protobuf::Field::TYPE_UNKNOWN ||
627       field.kind() == google::protobuf::Field::TYPE_MESSAGE) {
628     // Push a ProtoElement for location reporting purposes.
629     if (element_->proto3()) {
630       element_.reset(new ProtoElement(element_.release(), &field, type, false));
631     }
632     InvalidValue(field.type_url().empty()
633                      ? google::protobuf::Field_Kind_Name(field.kind())
634                      : field.type_url(),
635                  data.ValueAsStringOrDefault(""));
636     element_.reset(element()->pop());
637     return this;
638   }
639 
640   switch (field.kind()) {
641     case google::protobuf::Field::TYPE_INT32: {
642       status = WriteInt32(field.number(), data, stream_.get());
643       break;
644     }
645     case google::protobuf::Field::TYPE_SFIXED32: {
646       status = WriteSFixed32(field.number(), data, stream_.get());
647       break;
648     }
649     case google::protobuf::Field::TYPE_SINT32: {
650       status = WriteSInt32(field.number(), data, stream_.get());
651       break;
652     }
653     case google::protobuf::Field::TYPE_FIXED32: {
654       status = WriteFixed32(field.number(), data, stream_.get());
655       break;
656     }
657     case google::protobuf::Field::TYPE_UINT32: {
658       status = WriteUInt32(field.number(), data, stream_.get());
659       break;
660     }
661     case google::protobuf::Field::TYPE_INT64: {
662       status = WriteInt64(field.number(), data, stream_.get());
663       break;
664     }
665     case google::protobuf::Field::TYPE_SFIXED64: {
666       status = WriteSFixed64(field.number(), data, stream_.get());
667       break;
668     }
669     case google::protobuf::Field::TYPE_SINT64: {
670       status = WriteSInt64(field.number(), data, stream_.get());
671       break;
672     }
673     case google::protobuf::Field::TYPE_FIXED64: {
674       status = WriteFixed64(field.number(), data, stream_.get());
675       break;
676     }
677     case google::protobuf::Field::TYPE_UINT64: {
678       status = WriteUInt64(field.number(), data, stream_.get());
679       break;
680     }
681     case google::protobuf::Field::TYPE_DOUBLE: {
682       status = WriteDouble(field.number(), data, stream_.get());
683       break;
684     }
685     case google::protobuf::Field::TYPE_FLOAT: {
686       status = WriteFloat(field.number(), data, stream_.get());
687       break;
688     }
689     case google::protobuf::Field::TYPE_BOOL: {
690       status = WriteBool(field.number(), data, stream_.get());
691       break;
692     }
693     case google::protobuf::Field::TYPE_BYTES: {
694       status = WriteBytes(field.number(), data, stream_.get());
695       break;
696     }
697     case google::protobuf::Field::TYPE_STRING: {
698       status = WriteString(field.number(), data, stream_.get());
699       break;
700     }
701     case google::protobuf::Field::TYPE_ENUM: {
702       status = WriteEnum(
703           field.number(), data, typeinfo_->GetEnumByTypeUrl(field.type_url()),
704           stream_.get(), use_lower_camel_for_enums_,
705           case_insensitive_enum_parsing_, ignore_unknown_enum_values_);
706       break;
707     }
708     default:  // TYPE_GROUP or TYPE_MESSAGE
709       status =
710           Status(util::error::INVALID_ARGUMENT, data.ToString().value());
711   }
712 
713   if (!status.ok()) {
714     // Push a ProtoElement for location reporting purposes.
715     if (element_->proto3()) {
716       element_.reset(new ProtoElement(element_.release(), &field, type, false));
717     }
718     InvalidValue(google::protobuf::Field_Kind_Name(field.kind()),
719                  status.message());
720     element_.reset(element()->pop());
721     return this;
722   }
723 
724   if (!element_->proto3()) element_.reset(element()->pop());
725 
726   return this;
727 }
728 
BeginNamed(StringPiece name,bool is_list)729 const google::protobuf::Field* ProtoWriter::BeginNamed(StringPiece name,
730                                                        bool is_list) {
731   if (invalid_depth_ > 0) {
732     ++invalid_depth_;
733     return nullptr;
734   }
735   const google::protobuf::Field* field = Lookup(name);
736   if (field == nullptr) {
737     ++invalid_depth_;
738     // InvalidName() already called in Lookup().
739     return nullptr;
740   }
741   if (is_list && !IsRepeated(*field)) {
742     ++invalid_depth_;
743     InvalidName(name, "Proto field is not repeating, cannot start list.");
744     return nullptr;
745   }
746   return field;
747 }
748 
Lookup(StringPiece unnormalized_name)749 const google::protobuf::Field* ProtoWriter::Lookup(
750     StringPiece unnormalized_name) {
751   ProtoElement* e = element();
752   if (e == nullptr) {
753     InvalidName(unnormalized_name, "Root element must be a message.");
754     return nullptr;
755   }
756   if (unnormalized_name.empty()) {
757     // Objects in repeated field inherit the same field descriptor.
758     if (e->parent_field() == nullptr) {
759       InvalidName(unnormalized_name, "Proto fields must have a name.");
760     } else if (!IsRepeated(*e->parent_field())) {
761       InvalidName(unnormalized_name, "Proto fields must have a name.");
762       return nullptr;
763     }
764     return e->parent_field();
765   }
766   const google::protobuf::Field* field =
767       typeinfo_->FindField(&e->type(), unnormalized_name);
768   if (field == nullptr && !ignore_unknown_fields_) {
769     InvalidName(unnormalized_name, "Cannot find field.");
770   }
771   return field;
772 }
773 
LookupType(const google::protobuf::Field * field)774 const google::protobuf::Type* ProtoWriter::LookupType(
775     const google::protobuf::Field* field) {
776   return ((field->kind() == google::protobuf::Field::TYPE_MESSAGE ||
777            field->kind() == google::protobuf::Field::TYPE_GROUP)
778               ? typeinfo_->GetTypeByTypeUrl(field->type_url())
779               : &element_->type());
780 }
781 
WriteRootMessage()782 void ProtoWriter::WriteRootMessage() {
783   GOOGLE_DCHECK(!done_);
784   int curr_pos = 0;
785   // Calls the destructor of CodedOutputStream to remove any uninitialized
786   // memory from the Cord before we read it.
787   stream_.reset(nullptr);
788   const void* data;
789   int length;
790   io::ArrayInputStream input_stream(buffer_.data(), buffer_.size());
791   while (input_stream.Next(&data, &length)) {
792     if (length == 0) continue;
793     int num_bytes = length;
794     // Write up to where we need to insert the size field.
795     // The number of bytes we may write is the smaller of:
796     //   - the current fragment size
797     //   - the distance to the next position where a size field needs to be
798     //     inserted.
799     if (!size_insert_.empty() &&
800         size_insert_.front().pos - curr_pos < num_bytes) {
801       num_bytes = size_insert_.front().pos - curr_pos;
802     }
803     output_->Append(static_cast<const char*>(data), num_bytes);
804     if (num_bytes < length) {
805       input_stream.BackUp(length - num_bytes);
806     }
807     curr_pos += num_bytes;
808     // Insert the size field.
809     //   size_insert_.front():      the next <index, size> pair to be written.
810     //   size_insert_.front().pos:  position of the size field.
811     //   size_insert_.front().size: the size (integer) to be inserted.
812     if (!size_insert_.empty() && curr_pos == size_insert_.front().pos) {
813       // Varint32 occupies at most 10 bytes.
814       uint8 insert_buffer[10];
815       uint8* insert_buffer_pos = CodedOutputStream::WriteVarint32ToArray(
816           size_insert_.front().size, insert_buffer);
817       output_->Append(reinterpret_cast<const char*>(insert_buffer),
818                       insert_buffer_pos - insert_buffer);
819       size_insert_.pop_front();
820     }
821   }
822   output_->Flush();
823   stream_.reset(new CodedOutputStream(&adapter_));
824   done_ = true;
825 }
826 
WriteTag(const google::protobuf::Field & field)827 void ProtoWriter::WriteTag(const google::protobuf::Field& field) {
828   WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType(
829       static_cast<WireFormatLite::FieldType>(field.kind()));
830   stream_->WriteTag(WireFormatLite::MakeTag(field.number(), wire_type));
831 }
832 
833 
834 }  // namespace converter
835 }  // namespace util
836 }  // namespace protobuf
837 }  // namespace google
838