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 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 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 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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 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 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 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 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 377 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 401 bool ProtoWriter::ProtoElement::IsOneofIndexTaken(int32 index) { 402 return ContainsKey(oneof_indices_, index); 403 } 404 405 void ProtoWriter::ProtoElement::TakeOneofIndex(int32 index) { 406 InsertIfNotPresent(&oneof_indices_, index); 407 } 408 409 void ProtoWriter::InvalidName(StringPiece unknown_name, StringPiece message) { 410 listener_->InvalidName(location(), ToSnakeCase(unknown_name), message); 411 } 412 413 void ProtoWriter::InvalidValue(StringPiece type_name, StringPiece value) { 414 listener_->InvalidValue(location(), type_name, value); 415 } 416 417 void ProtoWriter::MissingField(StringPiece missing_name) { 418 listener_->MissingField(location(), missing_name); 419 } 420 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 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 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 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 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 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 539 bool ProtoWriter::IsRepeated(const google::protobuf::Field& field) { 540 return field.cardinality() == 541 google::protobuf::Field_Cardinality_CARDINALITY_REPEATED; 542 } 543 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 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 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 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 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 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 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 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