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