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/protostream_objectwriter.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 util::error::INVALID_ARGUMENT; 55 using util::Status; 56 using util::StatusOr; 57 58 59 ProtoStreamObjectWriter::ProtoStreamObjectWriter( 60 TypeResolver* type_resolver, const google::protobuf::Type& type, 61 strings::ByteSink* output, ErrorListener* listener, 62 const ProtoStreamObjectWriter::Options& options) 63 : ProtoWriter(type_resolver, type, output, listener), 64 master_type_(type), 65 current_(NULL), 66 options_(options) {} 67 68 ProtoStreamObjectWriter::ProtoStreamObjectWriter( 69 const TypeInfo* typeinfo, const google::protobuf::Type& type, 70 strings::ByteSink* output, ErrorListener* listener) 71 : ProtoWriter(typeinfo, type, output, listener), 72 master_type_(type), 73 current_(NULL), 74 options_(ProtoStreamObjectWriter::Options::Defaults()) {} 75 76 ProtoStreamObjectWriter::~ProtoStreamObjectWriter() { 77 if (current_ == NULL) return; 78 // Cleanup explicitly in order to avoid destructor stack overflow when input 79 // is deeply nested. 80 // Cast to BaseElement to avoid doing additional checks (like missing fields) 81 // during pop(). 82 google::protobuf::scoped_ptr<BaseElement> element( 83 static_cast<BaseElement*>(current_.get())->pop<BaseElement>()); 84 while (element != NULL) { 85 element.reset(element->pop<BaseElement>()); 86 } 87 } 88 89 namespace { 90 // Utility method to split a string representation of Timestamp or Duration and 91 // return the parts. 92 void SplitSecondsAndNanos(StringPiece input, StringPiece* seconds, 93 StringPiece* nanos) { 94 size_t idx = input.rfind('.'); 95 if (idx != string::npos) { 96 *seconds = input.substr(0, idx); 97 *nanos = input.substr(idx + 1); 98 } else { 99 *seconds = input; 100 *nanos = StringPiece(); 101 } 102 } 103 104 Status GetNanosFromStringPiece(StringPiece s_nanos, 105 const char* parse_failure_message, 106 const char* exceeded_limit_message, 107 int32* nanos) { 108 *nanos = 0; 109 110 // Count the number of leading 0s and consume them. 111 int num_leading_zeros = 0; 112 while (s_nanos.Consume("0")) { 113 num_leading_zeros++; 114 } 115 int32 i_nanos = 0; 116 // 's_nanos' contains fractional seconds -- i.e. 'nanos' is equal to 117 // "0." + s_nanos.ToString() seconds. An int32 is used for the 118 // conversion to 'nanos', rather than a double, so that there is no 119 // loss of precision. 120 if (!s_nanos.empty() && !safe_strto32(s_nanos.ToString(), &i_nanos)) { 121 return Status(INVALID_ARGUMENT, parse_failure_message); 122 } 123 if (i_nanos > kNanosPerSecond || i_nanos < 0) { 124 return Status(INVALID_ARGUMENT, exceeded_limit_message); 125 } 126 // s_nanos should only have digits. No whitespace. 127 if (s_nanos.find_first_not_of("0123456789") != StringPiece::npos) { 128 return Status(INVALID_ARGUMENT, parse_failure_message); 129 } 130 131 if (i_nanos > 0) { 132 // 'scale' is the number of digits to the right of the decimal 133 // point in "0." + s_nanos.ToString() 134 int32 scale = num_leading_zeros + s_nanos.size(); 135 // 'conversion' converts i_nanos into nanoseconds. 136 // conversion = kNanosPerSecond / static_cast<int32>(std::pow(10, scale)) 137 // For efficiency, we precompute the conversion factor. 138 int32 conversion = 0; 139 switch (scale) { 140 case 1: 141 conversion = 100000000; 142 break; 143 case 2: 144 conversion = 10000000; 145 break; 146 case 3: 147 conversion = 1000000; 148 break; 149 case 4: 150 conversion = 100000; 151 break; 152 case 5: 153 conversion = 10000; 154 break; 155 case 6: 156 conversion = 1000; 157 break; 158 case 7: 159 conversion = 100; 160 break; 161 case 8: 162 conversion = 10; 163 break; 164 case 9: 165 conversion = 1; 166 break; 167 default: 168 return Status(INVALID_ARGUMENT, exceeded_limit_message); 169 } 170 *nanos = i_nanos * conversion; 171 } 172 173 return Status::OK; 174 } 175 176 } // namespace 177 178 ProtoStreamObjectWriter::AnyWriter::AnyWriter(ProtoStreamObjectWriter* parent) 179 : parent_(parent), 180 ow_(), 181 invalid_(false), 182 data_(), 183 output_(&data_), 184 depth_(0), 185 is_well_known_type_(false), 186 well_known_type_render_(NULL) {} 187 188 ProtoStreamObjectWriter::AnyWriter::~AnyWriter() {} 189 190 void ProtoStreamObjectWriter::AnyWriter::StartObject(StringPiece name) { 191 ++depth_; 192 // If an object writer is absent, that means we have not called StartAny() 193 // before reaching here. This is an invalid state. StartAny() gets called 194 // whenever we see an "@type" being rendered (see AnyWriter::RenderDataPiece). 195 if (ow_ == NULL) { 196 // Make sure we are not already in an invalid state. This avoids making 197 // multiple unnecessary InvalidValue calls. 198 if (!invalid_) { 199 parent_->InvalidValue("Any", 200 StrCat("Missing or invalid @type for any field in ", 201 parent_->master_type_.name())); 202 invalid_ = true; 203 } 204 } else if (is_well_known_type_ && depth_ == 1) { 205 // For well-known types, the only other field besides "@type" should be a 206 // "value" field. 207 if (name != "value" && !invalid_) { 208 parent_->InvalidValue("Any", 209 "Expect a \"value\" field for well-known types."); 210 invalid_ = true; 211 } 212 ow_->StartObject(""); 213 } else { 214 // Forward the call to the child writer if: 215 // 1. the type is not a well-known type. 216 // 2. or, we are in a nested Any, Struct, or Value object. 217 ow_->StartObject(name); 218 } 219 } 220 221 bool ProtoStreamObjectWriter::AnyWriter::EndObject() { 222 --depth_; 223 // As long as depth_ >= 0, we know we haven't reached the end of Any. 224 // Propagate these EndObject() calls to the contained ow_. For regular 225 // message types, we propagate the end of Any as well. 226 if (ow_ != NULL && (depth_ >= 0 || !is_well_known_type_)) { 227 ow_->EndObject(); 228 } 229 // A negative depth_ implies that we have reached the end of Any 230 // object. Now we write out its contents. 231 if (depth_ < 0) { 232 WriteAny(); 233 return false; 234 } 235 return true; 236 } 237 238 void ProtoStreamObjectWriter::AnyWriter::StartList(StringPiece name) { 239 ++depth_; 240 // We expect ow_ to be present as this call only makes sense inside an Any. 241 if (ow_ == NULL) { 242 if (!invalid_) { 243 parent_->InvalidValue("Any", 244 StrCat("Missing or invalid @type for any field in ", 245 parent_->master_type_.name())); 246 invalid_ = true; 247 } 248 } else if (is_well_known_type_ && depth_ == 1) { 249 if (name != "value" && !invalid_) { 250 parent_->InvalidValue("Any", 251 "Expect a \"value\" field for well-known types."); 252 invalid_ = true; 253 } 254 ow_->StartList(""); 255 } else { 256 ow_->StartList(name); 257 } 258 } 259 260 void ProtoStreamObjectWriter::AnyWriter::EndList() { 261 --depth_; 262 if (depth_ < 0) { 263 GOOGLE_LOG(DFATAL) << "Mismatched EndList found, should not be possible"; 264 depth_ = 0; 265 } 266 // We don't write an error on the close, only on the open 267 if (ow_ != NULL) { 268 ow_->EndList(); 269 } 270 } 271 272 void ProtoStreamObjectWriter::AnyWriter::RenderDataPiece( 273 StringPiece name, const DataPiece& value) { 274 // Start an Any only at depth_ 0. Other RenderDataPiece calls with "@type" 275 // should go to the contained ow_ as they indicate nested Anys. 276 if (depth_ == 0 && ow_ == NULL && name == "@type") { 277 StartAny(value); 278 } else if (ow_ == NULL) { 279 if (!invalid_) { 280 parent_->InvalidValue("Any", 281 StrCat("Missing or invalid @type for any field in ", 282 parent_->master_type_.name())); 283 invalid_ = true; 284 } 285 } else if (depth_ == 0 && is_well_known_type_) { 286 if (name != "value" && !invalid_) { 287 parent_->InvalidValue("Any", 288 "Expect a \"value\" field for well-known types."); 289 invalid_ = true; 290 } 291 if (well_known_type_render_ == NULL) { 292 // Only Any and Struct don't have a special type render but both of 293 // them expect a JSON object (i.e., a StartObject() call). 294 if (!invalid_) { 295 parent_->InvalidValue("Any", "Expect a JSON object."); 296 invalid_ = true; 297 } 298 } else { 299 ow_->ProtoWriter::StartObject(""); 300 Status status = (*well_known_type_render_)(ow_.get(), value); 301 if (!status.ok()) ow_->InvalidValue("Any", status.error_message()); 302 ow_->ProtoWriter::EndObject(); 303 } 304 } else { 305 ow_->RenderDataPiece(name, value); 306 } 307 } 308 309 void ProtoStreamObjectWriter::AnyWriter::StartAny(const DataPiece& value) { 310 // Figure out the type url. This is a copy-paste from WriteString but we also 311 // need the value, so we can't just call through to that. 312 if (value.type() == DataPiece::TYPE_STRING) { 313 type_url_ = value.str().ToString(); 314 } else { 315 StatusOr<string> s = value.ToString(); 316 if (!s.ok()) { 317 parent_->InvalidValue("String", s.status().error_message()); 318 invalid_ = true; 319 return; 320 } 321 type_url_ = s.ValueOrDie(); 322 } 323 // Resolve the type url, and report an error if we failed to resolve it. 324 StatusOr<const google::protobuf::Type*> resolved_type = 325 parent_->typeinfo()->ResolveTypeUrl(type_url_); 326 if (!resolved_type.ok()) { 327 parent_->InvalidValue("Any", resolved_type.status().error_message()); 328 invalid_ = true; 329 return; 330 } 331 // At this point, type is never null. 332 const google::protobuf::Type* type = resolved_type.ValueOrDie(); 333 334 well_known_type_render_ = FindTypeRenderer(type_url_); 335 if (well_known_type_render_ != NULL || 336 // Explicitly list Any and Struct here because they don't have a 337 // custom renderer. 338 type->name() == kAnyType || type->name() == kStructType) { 339 is_well_known_type_ = true; 340 } 341 342 // Create our object writer and initialize it with the first StartObject 343 // call. 344 ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo(), *type, &output_, 345 parent_->listener())); 346 347 // Don't call StartObject() for well-known types yet. Depending on the 348 // type of actual data, we may not need to call StartObject(). For 349 // example: 350 // { 351 // "@type": "type.googleapis.com/google.protobuf.Value", 352 // "value": [1, 2, 3], 353 // } 354 // With the above JSON representation, we will only call StartList() on the 355 // contained ow_. 356 if (!is_well_known_type_) { 357 ow_->StartObject(""); 358 } 359 } 360 361 void ProtoStreamObjectWriter::AnyWriter::WriteAny() { 362 if (ow_ == NULL) { 363 // If we had no object writer, we never got any content, so just return 364 // immediately, which is equivalent to writing an empty Any. 365 return; 366 } 367 // Render the type_url and value fields directly to the stream. 368 // type_url has tag 1 and value has tag 2. 369 WireFormatLite::WriteString(1, type_url_, parent_->stream()); 370 if (!data_.empty()) { 371 WireFormatLite::WriteBytes(2, data_, parent_->stream()); 372 } 373 } 374 375 ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter* enclosing, 376 ItemType item_type, bool is_placeholder, 377 bool is_list) 378 : BaseElement(NULL), 379 ow_(enclosing), 380 any_(), 381 item_type_(item_type), 382 is_placeholder_(is_placeholder), 383 is_list_(is_list) { 384 if (item_type_ == ANY) { 385 any_.reset(new AnyWriter(ow_)); 386 } 387 } 388 389 ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter::Item* parent, 390 ItemType item_type, bool is_placeholder, 391 bool is_list) 392 : BaseElement(parent), 393 ow_(this->parent()->ow_), 394 any_(), 395 item_type_(item_type), 396 is_placeholder_(is_placeholder), 397 is_list_(is_list) { 398 if (item_type == ANY) { 399 any_.reset(new AnyWriter(ow_)); 400 } 401 } 402 403 bool ProtoStreamObjectWriter::Item::InsertMapKeyIfNotPresent( 404 StringPiece map_key) { 405 return InsertIfNotPresent(&map_keys_, map_key.ToString()); 406 } 407 408 ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject( 409 StringPiece name) { 410 if (invalid_depth() > 0) { 411 IncrementInvalidDepth(); 412 return this; 413 } 414 415 // Starting the root message. Create the root Item and return. 416 // ANY message type does not need special handling, just set the ItemType 417 // to ANY. 418 if (current_ == NULL) { 419 ProtoWriter::StartObject(name); 420 current_.reset(new Item( 421 this, master_type_.name() == kAnyType ? Item::ANY : Item::MESSAGE, 422 false, false)); 423 424 // If master type is a special type that needs extra values to be written to 425 // stream, we write those values. 426 if (master_type_.name() == kStructType) { 427 // Struct has a map<string, Value> field called "fields". 428 // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto 429 // "fields": [ 430 Push("fields", Item::MAP, true, true); 431 return this; 432 } 433 434 if (master_type_.name() == kStructValueType) { 435 // We got a StartObject call with google.protobuf.Value field. The only 436 // object within that type is a struct type. So start a struct. 437 // 438 // The struct field in Value type is named "struct_value" 439 // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto 440 // Also start the map field "fields" within the struct. 441 // "struct_value": { 442 // "fields": [ 443 Push("struct_value", Item::MESSAGE, true, false); 444 Push("fields", Item::MAP, true, true); 445 return this; 446 } 447 448 if (master_type_.name() == kStructListValueType) { 449 InvalidValue(kStructListValueType, 450 "Cannot start root message with ListValue."); 451 } 452 453 return this; 454 } 455 456 // Send all ANY events to AnyWriter. 457 if (current_->IsAny()) { 458 current_->any()->StartObject(name); 459 return this; 460 } 461 462 // If we are within a map, we render name as keys and send StartObject to the 463 // value field. 464 if (current_->IsMap()) { 465 if (!ValidMapKey(name)) { 466 IncrementInvalidDepth(); 467 return this; 468 } 469 470 // Map is a repeated field of message type with a "key" and a "value" field. 471 // https://developers.google.com/protocol-buffers/docs/proto3?hl=en#maps 472 // message MapFieldEntry { 473 // key_type key = 1; 474 // value_type value = 2; 475 // } 476 // 477 // repeated MapFieldEntry map_field = N; 478 // 479 // That means, we render the following element within a list (hence no 480 // name): 481 // { "key": "<name>", "value": { 482 Push("", Item::MESSAGE, false, false); 483 ProtoWriter::RenderDataPiece("key", 484 DataPiece(name, use_strict_base64_decoding())); 485 Push("value", Item::MESSAGE, true, false); 486 487 // Make sure we are valid so far after starting map fields. 488 if (invalid_depth() > 0) return this; 489 490 // If top of stack is g.p.Struct type, start the struct the map field within 491 // it. 492 if (element() != NULL && IsStruct(*element()->parent_field())) { 493 // Render "fields": [ 494 Push("fields", Item::MAP, true, true); 495 return this; 496 } 497 498 // If top of stack is g.p.Value type, start the Struct within it. 499 if (element() != NULL && IsStructValue(*element()->parent_field())) { 500 // Render 501 // "struct_value": { 502 // "fields": [ 503 Push("struct_value", Item::MESSAGE, true, false); 504 Push("fields", Item::MAP, true, true); 505 } 506 return this; 507 } 508 509 const google::protobuf::Field* field = BeginNamed(name, false); 510 if (field == NULL) return this; 511 512 if (IsStruct(*field)) { 513 // Start a struct object. 514 // Render 515 // "<name>": { 516 // "fields": { 517 Push(name, Item::MESSAGE, false, false); 518 Push("fields", Item::MAP, true, true); 519 return this; 520 } 521 522 if (IsStructValue(*field)) { 523 // We got a StartObject call with google.protobuf.Value field. The only 524 // object within that type is a struct type. So start a struct. 525 // Render 526 // "<name>": { 527 // "struct_value": { 528 // "fields": { 529 Push(name, Item::MESSAGE, false, false); 530 Push("struct_value", Item::MESSAGE, true, false); 531 Push("fields", Item::MAP, true, true); 532 return this; 533 } 534 535 if (IsMap(*field)) { 536 // Begin a map. A map is triggered by a StartObject() call if the current 537 // field has a map type. 538 // A map type is always repeated, hence set is_list to true. 539 // Render 540 // "<name>": [ 541 Push(name, Item::MAP, false, true); 542 return this; 543 } 544 545 // A regular message type. Pass it directly to ProtoWriter. 546 // Render 547 // "<name>": { 548 Push(name, IsAny(*field) ? Item::ANY : Item::MESSAGE, false, false); 549 return this; 550 } 551 552 ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndObject() { 553 if (invalid_depth() > 0) { 554 DecrementInvalidDepth(); 555 return this; 556 } 557 558 if (current_ == NULL) return this; 559 560 if (current_->IsAny()) { 561 if (current_->any()->EndObject()) return this; 562 } 563 564 Pop(); 565 566 return this; 567 } 568 569 ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) { 570 if (invalid_depth() > 0) { 571 IncrementInvalidDepth(); 572 return this; 573 } 574 575 // Since we cannot have a top-level repeated item in protobuf, the only way 576 // this is valid is if we start a special type google.protobuf.ListValue or 577 // google.protobuf.Value. 578 if (current_ == NULL) { 579 if (!name.empty()) { 580 InvalidName(name, "Root element should not be named."); 581 IncrementInvalidDepth(); 582 return this; 583 } 584 585 // If master type is a special type that needs extra values to be written to 586 // stream, we write those values. 587 if (master_type_.name() == kStructValueType) { 588 // We got a StartList with google.protobuf.Value master type. This means 589 // we have to start the "list_value" within google.protobuf.Value. 590 // 591 // See 592 // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto 593 // 594 // Render 595 // "<name>": { 596 // "list_value": { 597 // "values": [ // Start this list. 598 ProtoWriter::StartObject(name); 599 current_.reset(new Item(this, Item::MESSAGE, false, false)); 600 Push("list_value", Item::MESSAGE, true, false); 601 Push("values", Item::MESSAGE, true, true); 602 return this; 603 } 604 605 if (master_type_.name() == kStructListValueType) { 606 // We got a StartList with google.protobuf.ListValue master type. This 607 // means we have to start the "values" within google.protobuf.ListValue. 608 // 609 // Render 610 // "<name>": { 611 // "values": [ // Start this list. 612 ProtoWriter::StartObject(name); 613 current_.reset(new Item(this, Item::MESSAGE, false, false)); 614 Push("values", Item::MESSAGE, true, true); 615 return this; 616 } 617 618 // Send the event to ProtoWriter so proper errors can be reported. 619 // 620 // Render a regular list: 621 // "<name>": [ 622 ProtoWriter::StartList(name); 623 current_.reset(new Item(this, Item::MESSAGE, false, true)); 624 return this; 625 } 626 627 if (current_->IsAny()) { 628 current_->any()->StartList(name); 629 return this; 630 } 631 632 // If the top of stack is a map, we are starting a list value within a map. 633 // Since map does not allow repeated values, this can only happen when the map 634 // value is of a special type that renders a list in JSON. These can be one 635 // of 3 cases: 636 // i. We are rendering a list value within google.protobuf.Struct 637 // ii. We are rendering a list value within google.protobuf.Value 638 // iii. We are rendering a list value with type google.protobuf.ListValue. 639 if (current_->IsMap()) { 640 if (!ValidMapKey(name)) { 641 IncrementInvalidDepth(); 642 return this; 643 } 644 645 // Start the repeated map entry object. 646 // Render 647 // { "key": "<name>", "value": { 648 Push("", Item::MESSAGE, false, false); 649 ProtoWriter::RenderDataPiece("key", 650 DataPiece(name, use_strict_base64_decoding())); 651 Push("value", Item::MESSAGE, true, false); 652 653 // Make sure we are valid after pushing all above items. 654 if (invalid_depth() > 0) return this; 655 656 // case i and ii above. Start "list_value" field within g.p.Value 657 if (element() != NULL && element()->parent_field() != NULL) { 658 // Render 659 // "list_value": { 660 // "values": [ // Start this list 661 if (IsStructValue(*element()->parent_field())) { 662 Push("list_value", Item::MESSAGE, true, false); 663 Push("values", Item::MESSAGE, true, true); 664 return this; 665 } 666 667 // Render 668 // "values": [ 669 if (IsStructListValue(*element()->parent_field())) { 670 // case iii above. Bind directly to g.p.ListValue 671 Push("values", Item::MESSAGE, true, true); 672 return this; 673 } 674 } 675 676 // Report an error. 677 InvalidValue("Map", StrCat("Cannot have repeated items ('", name, 678 "') within a map.")); 679 return this; 680 } 681 682 // When name is empty and stack is not empty, we are rendering an item within 683 // a list. 684 if (name.empty()) { 685 if (element() != NULL && element()->parent_field() != NULL) { 686 if (IsStructValue(*element()->parent_field())) { 687 // Since it is g.p.Value, we bind directly to the list_value. 688 // Render 689 // { // g.p.Value item within the list 690 // "list_value": { 691 // "values": [ 692 Push("", Item::MESSAGE, false, false); 693 Push("list_value", Item::MESSAGE, true, false); 694 Push("values", Item::MESSAGE, true, true); 695 return this; 696 } 697 698 if (IsStructListValue(*element()->parent_field())) { 699 // Since it is g.p.ListValue, we bind to it directly. 700 // Render 701 // { // g.p.ListValue item within the list 702 // "values": [ 703 Push("", Item::MESSAGE, false, false); 704 Push("values", Item::MESSAGE, true, true); 705 return this; 706 } 707 } 708 709 // Pass the event to underlying ProtoWriter. 710 Push(name, Item::MESSAGE, false, true); 711 return this; 712 } 713 714 // name is not empty 715 const google::protobuf::Field* field = Lookup(name); 716 if (field == NULL) { 717 IncrementInvalidDepth(); 718 return this; 719 } 720 721 if (IsStructValue(*field)) { 722 // If g.p.Value is repeated, start that list. Otherwise, start the 723 // "list_value" within it. 724 if (IsRepeated(*field)) { 725 // Render it just like a regular repeated field. 726 // "<name>": [ 727 Push(name, Item::MESSAGE, false, true); 728 return this; 729 } 730 731 // Start the "list_value" field. 732 // Render 733 // "<name>": { 734 // "list_value": { 735 // "values": [ 736 Push(name, Item::MESSAGE, false, false); 737 Push("list_value", Item::MESSAGE, true, false); 738 Push("values", Item::MESSAGE, true, true); 739 return this; 740 } 741 742 if (IsStructListValue(*field)) { 743 // If g.p.ListValue is repeated, start that list. Otherwise, start the 744 // "values" within it. 745 if (IsRepeated(*field)) { 746 // Render it just like a regular repeated field. 747 // "<name>": [ 748 Push(name, Item::MESSAGE, false, true); 749 return this; 750 } 751 752 // Start the "values" field within g.p.ListValue. 753 // Render 754 // "<name>": { 755 // "values": [ 756 Push(name, Item::MESSAGE, false, false); 757 Push("values", Item::MESSAGE, true, true); 758 return this; 759 } 760 761 // If we are here, the field should be repeated. Report an error otherwise. 762 if (!IsRepeated(*field)) { 763 IncrementInvalidDepth(); 764 InvalidName(name, "Proto field is not repeating, cannot start list."); 765 return this; 766 } 767 768 if (IsMap(*field)) { 769 InvalidValue("Map", 770 StrCat("Cannot bind a list to map for field '", name, "'.")); 771 IncrementInvalidDepth(); 772 return this; 773 } 774 775 // Pass the event to ProtoWriter. 776 // Render 777 // "<name>": [ 778 Push(name, Item::MESSAGE, false, true); 779 return this; 780 } 781 782 ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndList() { 783 if (invalid_depth() > 0) { 784 DecrementInvalidDepth(); 785 return this; 786 } 787 788 if (current_ == NULL) return this; 789 790 if (current_->IsAny()) { 791 current_->any()->EndList(); 792 return this; 793 } 794 795 Pop(); 796 return this; 797 } 798 799 Status ProtoStreamObjectWriter::RenderStructValue(ProtoStreamObjectWriter* ow, 800 const DataPiece& data) { 801 string struct_field_name; 802 switch (data.type()) { 803 // Our JSON parser parses numbers as either int64, uint64, or double. 804 case DataPiece::TYPE_INT64: { 805 // If the option to treat integers as strings is set, then render them as 806 // strings. Otherwise, fallback to rendering them as double. 807 if (ow->options_.struct_integers_as_strings) { 808 StatusOr<int64> int_value = data.ToInt64(); 809 if (int_value.ok()) { 810 ow->ProtoWriter::RenderDataPiece( 811 "string_value", 812 DataPiece(SimpleItoa(int_value.ValueOrDie()), true)); 813 return Status::OK; 814 } 815 } 816 struct_field_name = "number_value"; 817 break; 818 } 819 case DataPiece::TYPE_UINT64: { 820 // If the option to treat integers as strings is set, then render them as 821 // strings. Otherwise, fallback to rendering them as double. 822 if (ow->options_.struct_integers_as_strings) { 823 StatusOr<uint64> int_value = data.ToUint64(); 824 if (int_value.ok()) { 825 ow->ProtoWriter::RenderDataPiece( 826 "string_value", 827 DataPiece(SimpleItoa(int_value.ValueOrDie()), true)); 828 return Status::OK; 829 } 830 } 831 struct_field_name = "number_value"; 832 break; 833 } 834 case DataPiece::TYPE_DOUBLE: { 835 struct_field_name = "number_value"; 836 break; 837 } 838 case DataPiece::TYPE_STRING: { 839 struct_field_name = "string_value"; 840 break; 841 } 842 case DataPiece::TYPE_BOOL: { 843 struct_field_name = "bool_value"; 844 break; 845 } 846 case DataPiece::TYPE_NULL: { 847 struct_field_name = "null_value"; 848 break; 849 } 850 default: { 851 return Status(INVALID_ARGUMENT, 852 "Invalid struct data type. Only number, string, boolean or " 853 "null values are supported."); 854 } 855 } 856 ow->ProtoWriter::RenderDataPiece(struct_field_name, data); 857 return Status::OK; 858 } 859 860 Status ProtoStreamObjectWriter::RenderTimestamp(ProtoStreamObjectWriter* ow, 861 const DataPiece& data) { 862 if (data.type() != DataPiece::TYPE_STRING) { 863 return Status(INVALID_ARGUMENT, 864 StrCat("Invalid data type for timestamp, value is ", 865 data.ValueAsStringOrDefault(""))); 866 } 867 868 StringPiece value(data.str()); 869 870 int64 seconds; 871 int32 nanos; 872 if (!::google::protobuf::internal::ParseTime(value.ToString(), &seconds, 873 &nanos)) { 874 return Status(INVALID_ARGUMENT, StrCat("Invalid time format: ", value)); 875 } 876 877 878 ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds)); 879 ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos)); 880 return Status::OK; 881 } 882 883 static inline util::Status RenderOneFieldPath(ProtoStreamObjectWriter* ow, 884 StringPiece path) { 885 ow->ProtoWriter::RenderDataPiece( 886 "paths", DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase), true)); 887 return Status::OK; 888 } 889 890 Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow, 891 const DataPiece& data) { 892 if (data.type() != DataPiece::TYPE_STRING) { 893 return Status(INVALID_ARGUMENT, 894 StrCat("Invalid data type for field mask, value is ", 895 data.ValueAsStringOrDefault(""))); 896 } 897 898 // TODO(tsun): figure out how to do proto descriptor based snake case 899 // conversions as much as possible. Because ToSnakeCase sometimes returns the 900 // wrong value. 901 google::protobuf::scoped_ptr<ResultCallback1<util::Status, StringPiece> > callback( 902 ::google::protobuf::internal::NewPermanentCallback(&RenderOneFieldPath, ow)); 903 return DecodeCompactFieldMaskPaths(data.str(), callback.get()); 904 } 905 906 Status ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow, 907 const DataPiece& data) { 908 if (data.type() != DataPiece::TYPE_STRING) { 909 return Status(INVALID_ARGUMENT, 910 StrCat("Invalid data type for duration, value is ", 911 data.ValueAsStringOrDefault(""))); 912 } 913 914 StringPiece value(data.str()); 915 916 if (!value.ends_with("s")) { 917 return Status(INVALID_ARGUMENT, 918 "Illegal duration format; duration must end with 's'"); 919 } 920 value = value.substr(0, value.size() - 1); 921 int sign = 1; 922 if (value.starts_with("-")) { 923 sign = -1; 924 value = value.substr(1); 925 } 926 927 StringPiece s_secs, s_nanos; 928 SplitSecondsAndNanos(value, &s_secs, &s_nanos); 929 uint64 unsigned_seconds; 930 if (!safe_strtou64(s_secs, &unsigned_seconds)) { 931 return Status(INVALID_ARGUMENT, 932 "Invalid duration format, failed to parse seconds"); 933 } 934 935 int32 nanos = 0; 936 Status nanos_status = GetNanosFromStringPiece( 937 s_nanos, "Invalid duration format, failed to parse nano seconds", 938 "Duration value exceeds limits", &nanos); 939 if (!nanos_status.ok()) { 940 return nanos_status; 941 } 942 nanos = sign * nanos; 943 944 int64 seconds = sign * unsigned_seconds; 945 if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds || 946 nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) { 947 return Status(INVALID_ARGUMENT, "Duration value exceeds limits"); 948 } 949 950 ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds)); 951 ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos)); 952 return Status::OK; 953 } 954 955 Status ProtoStreamObjectWriter::RenderWrapperType(ProtoStreamObjectWriter* ow, 956 const DataPiece& data) { 957 ow->ProtoWriter::RenderDataPiece("value", data); 958 return Status::OK; 959 } 960 961 ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece( 962 StringPiece name, const DataPiece& data) { 963 Status status; 964 if (invalid_depth() > 0) return this; 965 966 if (current_ == NULL) { 967 const TypeRenderer* type_renderer = 968 FindTypeRenderer(GetFullTypeWithUrl(master_type_.name())); 969 if (type_renderer == NULL) { 970 InvalidName(name, "Root element must be a message."); 971 return this; 972 } 973 // Render the special type. 974 // "<name>": { 975 // ... Render special type ... 976 // } 977 ProtoWriter::StartObject(name); 978 status = (*type_renderer)(this, data); 979 if (!status.ok()) { 980 InvalidValue(master_type_.name(), 981 StrCat("Field '", name, "', ", status.error_message())); 982 } 983 ProtoWriter::EndObject(); 984 return this; 985 } 986 987 if (current_->IsAny()) { 988 current_->any()->RenderDataPiece(name, data); 989 return this; 990 } 991 992 const google::protobuf::Field* field = NULL; 993 if (current_->IsMap()) { 994 if (!ValidMapKey(name)) return this; 995 996 // Render an item in repeated map list. 997 // { "key": "<name>", "value": 998 Push("", Item::MESSAGE, false, false); 999 ProtoWriter::RenderDataPiece("key", 1000 DataPiece(name, use_strict_base64_decoding())); 1001 field = Lookup("value"); 1002 if (field == NULL) { 1003 GOOGLE_LOG(DFATAL) << "Map does not have a value field."; 1004 return this; 1005 } 1006 1007 const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url()); 1008 if (type_renderer != NULL) { 1009 // Map's value type is a special type. Render it like a message: 1010 // "value": { 1011 // ... Render special type ... 1012 // } 1013 Push("value", Item::MESSAGE, true, false); 1014 status = (*type_renderer)(this, data); 1015 if (!status.ok()) { 1016 InvalidValue(field->type_url(), 1017 StrCat("Field '", name, "', ", status.error_message())); 1018 } 1019 Pop(); 1020 return this; 1021 } 1022 1023 // If we are rendering explicit null values and the backend proto field is 1024 // not of the google.protobuf.NullType type, we do nothing. 1025 if (data.type() == DataPiece::TYPE_NULL && 1026 field->type_url() != kStructNullValueTypeUrl) { 1027 Pop(); 1028 return this; 1029 } 1030 1031 // Render the map value as a primitive type. 1032 ProtoWriter::RenderDataPiece("value", data); 1033 Pop(); 1034 return this; 1035 } 1036 1037 field = Lookup(name); 1038 if (field == NULL) return this; 1039 1040 // Check if the field is of special type. Render it accordingly if so. 1041 const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url()); 1042 if (type_renderer != NULL) { 1043 Push(name, Item::MESSAGE, false, false); 1044 status = (*type_renderer)(this, data); 1045 if (!status.ok()) { 1046 InvalidValue(field->type_url(), 1047 StrCat("Field '", name, "', ", status.error_message())); 1048 } 1049 Pop(); 1050 return this; 1051 } 1052 1053 // If we are rendering explicit null values and the backend proto field is 1054 // not of the google.protobuf.NullType type, we do nothing. 1055 if (data.type() == DataPiece::TYPE_NULL && 1056 field->type_url() != kStructNullValueTypeUrl) { 1057 return this; 1058 } 1059 1060 ProtoWriter::RenderDataPiece(name, data); 1061 return this; 1062 } 1063 1064 // Map of functions that are responsible for rendering well known type 1065 // represented by the key. 1066 hash_map<string, ProtoStreamObjectWriter::TypeRenderer>* 1067 ProtoStreamObjectWriter::renderers_ = NULL; 1068 GOOGLE_PROTOBUF_DECLARE_ONCE(writer_renderers_init_); 1069 1070 void ProtoStreamObjectWriter::InitRendererMap() { 1071 renderers_ = new hash_map<string, ProtoStreamObjectWriter::TypeRenderer>(); 1072 (*renderers_)["type.googleapis.com/google.protobuf.Timestamp"] = 1073 &ProtoStreamObjectWriter::RenderTimestamp; 1074 (*renderers_)["type.googleapis.com/google.protobuf.Duration"] = 1075 &ProtoStreamObjectWriter::RenderDuration; 1076 (*renderers_)["type.googleapis.com/google.protobuf.FieldMask"] = 1077 &ProtoStreamObjectWriter::RenderFieldMask; 1078 (*renderers_)["type.googleapis.com/google.protobuf.Double"] = 1079 &ProtoStreamObjectWriter::RenderWrapperType; 1080 (*renderers_)["type.googleapis.com/google.protobuf.Float"] = 1081 &ProtoStreamObjectWriter::RenderWrapperType; 1082 (*renderers_)["type.googleapis.com/google.protobuf.Int64"] = 1083 &ProtoStreamObjectWriter::RenderWrapperType; 1084 (*renderers_)["type.googleapis.com/google.protobuf.UInt64"] = 1085 &ProtoStreamObjectWriter::RenderWrapperType; 1086 (*renderers_)["type.googleapis.com/google.protobuf.Int32"] = 1087 &ProtoStreamObjectWriter::RenderWrapperType; 1088 (*renderers_)["type.googleapis.com/google.protobuf.UInt32"] = 1089 &ProtoStreamObjectWriter::RenderWrapperType; 1090 (*renderers_)["type.googleapis.com/google.protobuf.Bool"] = 1091 &ProtoStreamObjectWriter::RenderWrapperType; 1092 (*renderers_)["type.googleapis.com/google.protobuf.String"] = 1093 &ProtoStreamObjectWriter::RenderWrapperType; 1094 (*renderers_)["type.googleapis.com/google.protobuf.Bytes"] = 1095 &ProtoStreamObjectWriter::RenderWrapperType; 1096 (*renderers_)["type.googleapis.com/google.protobuf.DoubleValue"] = 1097 &ProtoStreamObjectWriter::RenderWrapperType; 1098 (*renderers_)["type.googleapis.com/google.protobuf.FloatValue"] = 1099 &ProtoStreamObjectWriter::RenderWrapperType; 1100 (*renderers_)["type.googleapis.com/google.protobuf.Int64Value"] = 1101 &ProtoStreamObjectWriter::RenderWrapperType; 1102 (*renderers_)["type.googleapis.com/google.protobuf.UInt64Value"] = 1103 &ProtoStreamObjectWriter::RenderWrapperType; 1104 (*renderers_)["type.googleapis.com/google.protobuf.Int32Value"] = 1105 &ProtoStreamObjectWriter::RenderWrapperType; 1106 (*renderers_)["type.googleapis.com/google.protobuf.UInt32Value"] = 1107 &ProtoStreamObjectWriter::RenderWrapperType; 1108 (*renderers_)["type.googleapis.com/google.protobuf.BoolValue"] = 1109 &ProtoStreamObjectWriter::RenderWrapperType; 1110 (*renderers_)["type.googleapis.com/google.protobuf.StringValue"] = 1111 &ProtoStreamObjectWriter::RenderWrapperType; 1112 (*renderers_)["type.googleapis.com/google.protobuf.BytesValue"] = 1113 &ProtoStreamObjectWriter::RenderWrapperType; 1114 (*renderers_)["type.googleapis.com/google.protobuf.Value"] = 1115 &ProtoStreamObjectWriter::RenderStructValue; 1116 ::google::protobuf::internal::OnShutdown(&DeleteRendererMap); 1117 } 1118 1119 void ProtoStreamObjectWriter::DeleteRendererMap() { 1120 delete ProtoStreamObjectWriter::renderers_; 1121 renderers_ = NULL; 1122 } 1123 1124 ProtoStreamObjectWriter::TypeRenderer* 1125 ProtoStreamObjectWriter::FindTypeRenderer(const string& type_url) { 1126 ::google::protobuf::GoogleOnceInit(&writer_renderers_init_, &InitRendererMap); 1127 return FindOrNull(*renderers_, type_url); 1128 } 1129 1130 bool ProtoStreamObjectWriter::ValidMapKey(StringPiece unnormalized_name) { 1131 if (current_ == NULL) return true; 1132 1133 if (!current_->InsertMapKeyIfNotPresent(unnormalized_name)) { 1134 listener()->InvalidName( 1135 location(), unnormalized_name, 1136 StrCat("Repeated map key: '", unnormalized_name, "' is already set.")); 1137 return false; 1138 } 1139 1140 return true; 1141 } 1142 1143 void ProtoStreamObjectWriter::Push(StringPiece name, Item::ItemType item_type, 1144 bool is_placeholder, bool is_list) { 1145 is_list ? ProtoWriter::StartList(name) : ProtoWriter::StartObject(name); 1146 1147 // invalid_depth == 0 means it is a successful StartObject or StartList. 1148 if (invalid_depth() == 0) 1149 current_.reset( 1150 new Item(current_.release(), item_type, is_placeholder, is_list)); 1151 } 1152 1153 void ProtoStreamObjectWriter::Pop() { 1154 // Pop all placeholder items sending StartObject or StartList events to 1155 // ProtoWriter according to is_list value. 1156 while (current_ != NULL && current_->is_placeholder()) { 1157 PopOneElement(); 1158 } 1159 if (current_ != NULL) { 1160 PopOneElement(); 1161 } 1162 } 1163 1164 void ProtoStreamObjectWriter::PopOneElement() { 1165 current_->is_list() ? ProtoWriter::EndList() : ProtoWriter::EndObject(); 1166 current_.reset(current_->pop<Item>()); 1167 } 1168 1169 bool ProtoStreamObjectWriter::IsMap(const google::protobuf::Field& field) { 1170 if (field.type_url().empty() || 1171 field.kind() != google::protobuf::Field_Kind_TYPE_MESSAGE || 1172 field.cardinality() != 1173 google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) { 1174 return false; 1175 } 1176 const google::protobuf::Type* field_type = 1177 typeinfo()->GetTypeByTypeUrl(field.type_url()); 1178 1179 // TODO(xiaofeng): Unify option names. 1180 return GetBoolOptionOrDefault(field_type->options(), 1181 "google.protobuf.MessageOptions.map_entry", false) || 1182 GetBoolOptionOrDefault(field_type->options(), "map_entry", false); 1183 } 1184 1185 bool ProtoStreamObjectWriter::IsAny(const google::protobuf::Field& field) { 1186 return GetTypeWithoutUrl(field.type_url()) == kAnyType; 1187 } 1188 1189 bool ProtoStreamObjectWriter::IsStruct(const google::protobuf::Field& field) { 1190 return GetTypeWithoutUrl(field.type_url()) == kStructType; 1191 } 1192 1193 bool ProtoStreamObjectWriter::IsStructValue( 1194 const google::protobuf::Field& field) { 1195 return GetTypeWithoutUrl(field.type_url()) == kStructValueType; 1196 } 1197 1198 bool ProtoStreamObjectWriter::IsStructListValue( 1199 const google::protobuf::Field& field) { 1200 return GetTypeWithoutUrl(field.type_url()) == kStructListValueType; 1201 } 1202 1203 } // namespace converter 1204 } // namespace util 1205 } // namespace protobuf 1206 } // namespace google 1207