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