OLD | NEW |
1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
4 // | 4 // |
5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
7 // met: | 7 // met: |
8 // | 8 // |
9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 using util::StatusOr; | 57 using util::StatusOr; |
58 | 58 |
59 | 59 |
60 ProtoWriter::ProtoWriter(TypeResolver* type_resolver, | 60 ProtoWriter::ProtoWriter(TypeResolver* type_resolver, |
61 const google::protobuf::Type& type, | 61 const google::protobuf::Type& type, |
62 strings::ByteSink* output, ErrorListener* listener) | 62 strings::ByteSink* output, ErrorListener* listener) |
63 : master_type_(type), | 63 : master_type_(type), |
64 typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), | 64 typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), |
65 own_typeinfo_(true), | 65 own_typeinfo_(true), |
66 done_(false), | 66 done_(false), |
| 67 ignore_unknown_fields_(false), |
| 68 use_lower_camel_for_enums_(false), |
67 element_(NULL), | 69 element_(NULL), |
68 size_insert_(), | 70 size_insert_(), |
69 output_(output), | 71 output_(output), |
70 buffer_(), | 72 buffer_(), |
71 adapter_(&buffer_), | 73 adapter_(&buffer_), |
72 stream_(new CodedOutputStream(&adapter_)), | 74 stream_(new CodedOutputStream(&adapter_)), |
73 listener_(listener), | 75 listener_(listener), |
74 invalid_depth_(0), | 76 invalid_depth_(0), |
75 tracker_(new ObjectLocationTracker()) {} | 77 tracker_(new ObjectLocationTracker()) {} |
76 | 78 |
77 ProtoWriter::ProtoWriter(const TypeInfo* typeinfo, | 79 ProtoWriter::ProtoWriter(const TypeInfo* typeinfo, |
78 const google::protobuf::Type& type, | 80 const google::protobuf::Type& type, |
79 strings::ByteSink* output, ErrorListener* listener) | 81 strings::ByteSink* output, ErrorListener* listener) |
80 : master_type_(type), | 82 : master_type_(type), |
81 typeinfo_(typeinfo), | 83 typeinfo_(typeinfo), |
82 own_typeinfo_(false), | 84 own_typeinfo_(false), |
83 done_(false), | 85 done_(false), |
| 86 ignore_unknown_fields_(false), |
| 87 use_lower_camel_for_enums_(false), |
84 element_(NULL), | 88 element_(NULL), |
85 size_insert_(), | 89 size_insert_(), |
86 output_(output), | 90 output_(output), |
87 buffer_(), | 91 buffer_(), |
88 adapter_(&buffer_), | 92 adapter_(&buffer_), |
89 stream_(new CodedOutputStream(&adapter_)), | 93 stream_(new CodedOutputStream(&adapter_)), |
90 listener_(listener), | 94 listener_(listener), |
91 invalid_depth_(0), | 95 invalid_depth_(0), |
92 tracker_(new ObjectLocationTracker()) {} | 96 tracker_(new ObjectLocationTracker()) {} |
93 | 97 |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
255 StatusOr<string> s = data.ToString(); | 259 StatusOr<string> s = data.ToString(); |
256 if (s.ok()) { | 260 if (s.ok()) { |
257 WireFormatLite::WriteString(field_number, s.ValueOrDie(), stream); | 261 WireFormatLite::WriteString(field_number, s.ValueOrDie(), stream); |
258 } | 262 } |
259 return s.status(); | 263 return s.status(); |
260 } | 264 } |
261 | 265 |
262 // Writes an ENUM field, including tag, to the stream. | 266 // Writes an ENUM field, including tag, to the stream. |
263 inline Status WriteEnum(int field_number, const DataPiece& data, | 267 inline Status WriteEnum(int field_number, const DataPiece& data, |
264 const google::protobuf::Enum* enum_type, | 268 const google::protobuf::Enum* enum_type, |
265 CodedOutputStream* stream) { | 269 CodedOutputStream* stream, |
266 StatusOr<int> e = data.ToEnum(enum_type); | 270 bool use_lower_camel_for_enums) { |
| 271 StatusOr<int> e = data.ToEnum(enum_type, use_lower_camel_for_enums); |
267 if (e.ok()) { | 272 if (e.ok()) { |
268 WireFormatLite::WriteEnum(field_number, e.ValueOrDie(), stream); | 273 WireFormatLite::WriteEnum(field_number, e.ValueOrDie(), stream); |
269 } | 274 } |
270 return e.status(); | 275 return e.status(); |
271 } | 276 } |
272 | 277 |
273 // Given a google::protobuf::Type, returns the set of all required fields. | 278 // Given a google::protobuf::Type, returns the set of all required fields. |
274 std::set<const google::protobuf::Field*> GetRequiredFields( | 279 std::set<const google::protobuf::Field*> GetRequiredFields( |
275 const google::protobuf::Type& type) { | 280 const google::protobuf::Type& type) { |
276 std::set<const google::protobuf::Field*> required; | 281 std::set<const google::protobuf::Field*> required; |
277 for (int i = 0; i < type.fields_size(); i++) { | 282 for (int i = 0; i < type.fields_size(); i++) { |
278 const google::protobuf::Field& field = type.fields(i); | 283 const google::protobuf::Field& field = type.fields(i); |
279 if (field.cardinality() == | 284 if (field.cardinality() == |
280 google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) { | 285 google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) { |
281 required.insert(&field); | 286 required.insert(&field); |
282 } | 287 } |
283 } | 288 } |
284 return required; | 289 return required; |
285 } | 290 } |
286 | 291 |
287 } // namespace | 292 } // namespace |
288 | 293 |
289 ProtoWriter::ProtoElement::ProtoElement(const TypeInfo* typeinfo, | 294 ProtoWriter::ProtoElement::ProtoElement(const TypeInfo* typeinfo, |
290 const google::protobuf::Type& type, | 295 const google::protobuf::Type& type, |
291 ProtoWriter* enclosing) | 296 ProtoWriter* enclosing) |
292 : BaseElement(NULL), | 297 : BaseElement(NULL), |
293 ow_(enclosing), | 298 ow_(enclosing), |
294 parent_field_(NULL), | 299 parent_field_(NULL), |
295 typeinfo_(typeinfo), | 300 typeinfo_(typeinfo), |
| 301 proto3_(type.syntax() == google::protobuf::SYNTAX_PROTO3), |
296 type_(type), | 302 type_(type), |
297 required_fields_(GetRequiredFields(type)), | |
298 size_index_(-1), | 303 size_index_(-1), |
299 array_index_(-1) {} | 304 array_index_(-1), |
| 305 // oneof_indices_ values are 1-indexed (0 means not present). |
| 306 oneof_indices_(type.oneofs_size() + 1) { |
| 307 if (!proto3_) { |
| 308 required_fields_ = GetRequiredFields(type_); |
| 309 } |
| 310 } |
300 | 311 |
301 ProtoWriter::ProtoElement::ProtoElement(ProtoWriter::ProtoElement* parent, | 312 ProtoWriter::ProtoElement::ProtoElement(ProtoWriter::ProtoElement* parent, |
302 const google::protobuf::Field* field, | 313 const google::protobuf::Field* field, |
303 const google::protobuf::Type& type, | 314 const google::protobuf::Type& type, |
304 bool is_list) | 315 bool is_list) |
305 : BaseElement(parent), | 316 : BaseElement(parent), |
306 ow_(this->parent()->ow_), | 317 ow_(this->parent()->ow_), |
307 parent_field_(field), | 318 parent_field_(field), |
308 typeinfo_(this->parent()->typeinfo_), | 319 typeinfo_(this->parent()->typeinfo_), |
| 320 proto3_(type.syntax() == google::protobuf::SYNTAX_PROTO3), |
309 type_(type), | 321 type_(type), |
310 size_index_( | 322 size_index_( |
311 !is_list && field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE | 323 !is_list && field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE |
312 ? ow_->size_insert_.size() | 324 ? ow_->size_insert_.size() |
313 : -1), | 325 : -1), |
314 array_index_(is_list ? 0 : -1) { | 326 array_index_(is_list ? 0 : -1), |
| 327 // oneof_indices_ values are 1-indexed (0 means not present). |
| 328 oneof_indices_(type_.oneofs_size() + 1) { |
315 if (!is_list) { | 329 if (!is_list) { |
316 if (ow_->IsRepeated(*field)) { | 330 if (ow_->IsRepeated(*field)) { |
317 // Update array_index_ if it is an explicit list. | 331 // Update array_index_ if it is an explicit list. |
318 if (this->parent()->array_index_ >= 0) this->parent()->array_index_++; | 332 if (this->parent()->array_index_ >= 0) this->parent()->array_index_++; |
319 } else { | 333 } else if (!proto3_) { |
| 334 // For required fields tracking. |
320 this->parent()->RegisterField(field); | 335 this->parent()->RegisterField(field); |
321 } | 336 } |
322 | 337 |
323 if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) { | 338 if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) { |
324 required_fields_ = GetRequiredFields(type_); | 339 if (!proto3_) { |
| 340 required_fields_ = GetRequiredFields(type_); |
| 341 } |
325 int start_pos = ow_->stream_->ByteCount(); | 342 int start_pos = ow_->stream_->ByteCount(); |
326 // length of serialized message is the final buffer position minus | 343 // length of serialized message is the final buffer position minus |
327 // starting buffer position, plus length adjustments for size fields | 344 // starting buffer position, plus length adjustments for size fields |
328 // of any nested messages. We start with -start_pos here, so we only | 345 // 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. | 346 // need to add the final buffer position to it at the end. |
330 SizeInfo info = {start_pos, -start_pos}; | 347 SizeInfo info = {start_pos, -start_pos}; |
331 ow_->size_insert_.push_back(info); | 348 ow_->size_insert_.push_back(info); |
332 } | 349 } |
333 } | 350 } |
334 } | 351 } |
335 | 352 |
336 ProtoWriter::ProtoElement* ProtoWriter::ProtoElement::pop() { | 353 ProtoWriter::ProtoElement* ProtoWriter::ProtoElement::pop() { |
337 // Calls the registered error listener for any required field(s) not yet | 354 if (!proto3_) { |
338 // seen. | 355 // Calls the registered error listener for any required field(s) not yet |
339 for (set<const google::protobuf::Field*>::iterator it = | 356 // seen. |
340 required_fields_.begin(); | 357 for (std::set<const google::protobuf::Field*>::iterator it = |
341 it != required_fields_.end(); ++it) { | 358 required_fields_.begin(); |
342 ow_->MissingField((*it)->name()); | 359 it != required_fields_.end(); ++it) { |
| 360 ow_->MissingField((*it)->name()); |
| 361 } |
343 } | 362 } |
344 // Computes the total number of proto bytes used by a message, also adjusts | 363 // 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. | 364 // 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. | 365 // If size_index_ < 0, this is not a message, so no size field is added. |
347 if (size_index_ >= 0) { | 366 if (size_index_ >= 0) { |
348 // Add the final buffer position to compute the total length of this | 367 // Add the final buffer position to compute the total length of this |
349 // serialized message. The stored value (before this addition) already | 368 // serialized message. The stored value (before this addition) already |
350 // contains the total length of the size fields of all nested messages | 369 // contains the total length of the size fields of all nested messages |
351 // minus the initial buffer position. | 370 // minus the initial buffer position. |
352 ow_->size_insert_[size_index_].size += ow_->stream_->ByteCount(); | 371 ow_->size_insert_[size_index_].size += ow_->stream_->ByteCount(); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
392 StrAppend(&loc, "[\"", CEscape(name), "\"]"); | 411 StrAppend(&loc, "[\"", CEscape(name), "\"]"); |
393 } | 412 } |
394 } | 413 } |
395 if (ow_->IsRepeated(*parent_field_) && array_index_ > 0) { | 414 if (ow_->IsRepeated(*parent_field_) && array_index_ > 0) { |
396 StrAppend(&loc, "[", array_index_ - 1, "]"); | 415 StrAppend(&loc, "[", array_index_ - 1, "]"); |
397 } | 416 } |
398 return loc.empty() ? "." : loc; | 417 return loc.empty() ? "." : loc; |
399 } | 418 } |
400 | 419 |
401 bool ProtoWriter::ProtoElement::IsOneofIndexTaken(int32 index) { | 420 bool ProtoWriter::ProtoElement::IsOneofIndexTaken(int32 index) { |
402 return ContainsKey(oneof_indices_, index); | 421 return oneof_indices_[index]; |
403 } | 422 } |
404 | 423 |
405 void ProtoWriter::ProtoElement::TakeOneofIndex(int32 index) { | 424 void ProtoWriter::ProtoElement::TakeOneofIndex(int32 index) { |
406 InsertIfNotPresent(&oneof_indices_, index); | 425 oneof_indices_[index] = true; |
407 } | 426 } |
408 | 427 |
409 void ProtoWriter::InvalidName(StringPiece unknown_name, StringPiece message) { | 428 void ProtoWriter::InvalidName(StringPiece unknown_name, StringPiece message) { |
410 listener_->InvalidName(location(), ToSnakeCase(unknown_name), message); | 429 listener_->InvalidName(location(), ToSnakeCase(unknown_name), message); |
411 } | 430 } |
412 | 431 |
413 void ProtoWriter::InvalidValue(StringPiece type_name, StringPiece value) { | 432 void ProtoWriter::InvalidValue(StringPiece type_name, StringPiece value) { |
414 listener_->InvalidValue(location(), type_name, value); | 433 listener_->InvalidValue(location(), type_name, value); |
415 } | 434 } |
416 | 435 |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
554 return this; | 573 return this; |
555 } | 574 } |
556 | 575 |
557 ProtoWriter* ProtoWriter::RenderPrimitiveField( | 576 ProtoWriter* ProtoWriter::RenderPrimitiveField( |
558 const google::protobuf::Field& field, const google::protobuf::Type& type, | 577 const google::protobuf::Field& field, const google::protobuf::Type& type, |
559 const DataPiece& data) { | 578 const DataPiece& data) { |
560 Status status; | 579 Status status; |
561 | 580 |
562 // Pushing a ProtoElement and then pop it off at the end for 2 purposes: | 581 // Pushing a ProtoElement and then pop it off at the end for 2 purposes: |
563 // error location reporting and required field accounting. | 582 // error location reporting and required field accounting. |
564 element_.reset(new ProtoElement(element_.release(), &field, type, false)); | 583 // |
| 584 // For proto3, since there is no required field tracking, we only need to push |
| 585 // ProtoElement for error cases. |
| 586 if (!element_->proto3()) { |
| 587 element_.reset(new ProtoElement(element_.release(), &field, type, false)); |
| 588 } |
565 | 589 |
566 if (field.kind() == google::protobuf::Field_Kind_TYPE_UNKNOWN || | 590 if (field.kind() == google::protobuf::Field_Kind_TYPE_UNKNOWN || |
567 field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) { | 591 field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) { |
| 592 // Push a ProtoElement for location reporting purposes. |
| 593 if (element_->proto3()) { |
| 594 element_.reset(new ProtoElement(element_.release(), &field, type, false)); |
| 595 } |
568 InvalidValue(field.type_url().empty() | 596 InvalidValue(field.type_url().empty() |
569 ? google::protobuf::Field_Kind_Name(field.kind()) | 597 ? google::protobuf::Field_Kind_Name(field.kind()) |
570 : field.type_url(), | 598 : field.type_url(), |
571 data.ValueAsStringOrDefault("")); | 599 data.ValueAsStringOrDefault("")); |
572 element_.reset(element()->pop()); | 600 element_.reset(element()->pop()); |
573 return this; | 601 return this; |
574 } | 602 } |
575 | 603 |
576 switch (field.kind()) { | 604 switch (field.kind()) { |
577 case google::protobuf::Field_Kind_TYPE_INT32: { | 605 case google::protobuf::Field_Kind_TYPE_INT32: { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
630 status = WriteBytes(field.number(), data, stream_.get()); | 658 status = WriteBytes(field.number(), data, stream_.get()); |
631 break; | 659 break; |
632 } | 660 } |
633 case google::protobuf::Field_Kind_TYPE_STRING: { | 661 case google::protobuf::Field_Kind_TYPE_STRING: { |
634 status = WriteString(field.number(), data, stream_.get()); | 662 status = WriteString(field.number(), data, stream_.get()); |
635 break; | 663 break; |
636 } | 664 } |
637 case google::protobuf::Field_Kind_TYPE_ENUM: { | 665 case google::protobuf::Field_Kind_TYPE_ENUM: { |
638 status = WriteEnum(field.number(), data, | 666 status = WriteEnum(field.number(), data, |
639 typeinfo_->GetEnumByTypeUrl(field.type_url()), | 667 typeinfo_->GetEnumByTypeUrl(field.type_url()), |
640 stream_.get()); | 668 stream_.get(), use_lower_camel_for_enums_); |
641 break; | 669 break; |
642 } | 670 } |
643 default: // TYPE_GROUP or TYPE_MESSAGE | 671 default: // TYPE_GROUP or TYPE_MESSAGE |
644 status = Status(INVALID_ARGUMENT, data.ToString().ValueOrDie()); | 672 status = Status(INVALID_ARGUMENT, data.ToString().ValueOrDie()); |
645 } | 673 } |
646 | 674 |
647 if (!status.ok()) { | 675 if (!status.ok()) { |
| 676 // Push a ProtoElement for location reporting purposes. |
| 677 if (element_->proto3()) { |
| 678 element_.reset(new ProtoElement(element_.release(), &field, type, false)); |
| 679 } |
648 InvalidValue(google::protobuf::Field_Kind_Name(field.kind()), | 680 InvalidValue(google::protobuf::Field_Kind_Name(field.kind()), |
649 status.error_message()); | 681 status.error_message()); |
| 682 element_.reset(element()->pop()); |
| 683 return this; |
650 } | 684 } |
651 | 685 |
652 element_.reset(element()->pop()); | 686 if (!element_->proto3()) element_.reset(element()->pop()); |
| 687 |
653 return this; | 688 return this; |
654 } | 689 } |
655 | 690 |
656 const google::protobuf::Field* ProtoWriter::BeginNamed(StringPiece name, | 691 const google::protobuf::Field* ProtoWriter::BeginNamed(StringPiece name, |
657 bool is_list) { | 692 bool is_list) { |
658 if (invalid_depth_ > 0) { | 693 if (invalid_depth_ > 0) { |
659 ++invalid_depth_; | 694 ++invalid_depth_; |
660 return NULL; | 695 return NULL; |
661 } | 696 } |
662 const google::protobuf::Field* field = Lookup(name); | 697 const google::protobuf::Field* field = Lookup(name); |
(...skipping 22 matching lines...) Expand all Loading... |
685 if (e->parent_field() == NULL) { | 720 if (e->parent_field() == NULL) { |
686 InvalidName(unnormalized_name, "Proto fields must have a name."); | 721 InvalidName(unnormalized_name, "Proto fields must have a name."); |
687 } else if (!IsRepeated(*e->parent_field())) { | 722 } else if (!IsRepeated(*e->parent_field())) { |
688 InvalidName(unnormalized_name, "Proto fields must have a name."); | 723 InvalidName(unnormalized_name, "Proto fields must have a name."); |
689 return NULL; | 724 return NULL; |
690 } | 725 } |
691 return e->parent_field(); | 726 return e->parent_field(); |
692 } | 727 } |
693 const google::protobuf::Field* field = | 728 const google::protobuf::Field* field = |
694 typeinfo_->FindField(&e->type(), unnormalized_name); | 729 typeinfo_->FindField(&e->type(), unnormalized_name); |
695 if (field == NULL) InvalidName(unnormalized_name, "Cannot find field."); | 730 if (field == NULL && !ignore_unknown_fields_) { |
| 731 InvalidName(unnormalized_name, "Cannot find field."); |
| 732 } |
696 return field; | 733 return field; |
697 } | 734 } |
698 | 735 |
699 const google::protobuf::Type* ProtoWriter::LookupType( | 736 const google::protobuf::Type* ProtoWriter::LookupType( |
700 const google::protobuf::Field* field) { | 737 const google::protobuf::Field* field) { |
701 return ((field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE || | 738 return ((field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE || |
702 field->kind() == google::protobuf::Field_Kind_TYPE_GROUP) | 739 field->kind() == google::protobuf::Field_Kind_TYPE_GROUP) |
703 ? typeinfo_->GetTypeByTypeUrl(field->type_url()) | 740 ? typeinfo_->GetTypeByTypeUrl(field->type_url()) |
704 : &element_->type()); | 741 : &element_->type()); |
705 } | 742 } |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
753 WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType( | 790 WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType( |
754 static_cast<WireFormatLite::FieldType>(field.kind())); | 791 static_cast<WireFormatLite::FieldType>(field.kind())); |
755 stream_->WriteTag(WireFormatLite::MakeTag(field.number(), wire_type)); | 792 stream_->WriteTag(WireFormatLite::MakeTag(field.number(), wire_type)); |
756 } | 793 } |
757 | 794 |
758 | 795 |
759 } // namespace converter | 796 } // namespace converter |
760 } // namespace util | 797 } // namespace util |
761 } // namespace protobuf | 798 } // namespace protobuf |
762 } // namespace google | 799 } // namespace google |
OLD | NEW |