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