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_objectsource.h> 32 33 #include <utility> 34 35 #include <google/protobuf/stubs/casts.h> 36 #include <google/protobuf/stubs/logging.h> 37 #include <google/protobuf/stubs/common.h> 38 #include <google/protobuf/stubs/stringprintf.h> 39 #include <google/protobuf/stubs/time.h> 40 #include <google/protobuf/io/coded_stream.h> 41 #include <google/protobuf/io/zero_copy_stream_impl.h> 42 #include <google/protobuf/descriptor.h> 43 #include <google/protobuf/wire_format.h> 44 #include <google/protobuf/wire_format_lite.h> 45 #include <google/protobuf/util/internal/field_mask_utility.h> 46 #include <google/protobuf/util/internal/constants.h> 47 #include <google/protobuf/util/internal/utility.h> 48 #include <google/protobuf/stubs/strutil.h> 49 #include <google/protobuf/stubs/map_util.h> 50 #include <google/protobuf/stubs/status_macros.h> 51 52 53 namespace google { 54 namespace protobuf { 55 namespace util { 56 using util::Status; 57 using util::StatusOr; 58 namespace error { 59 using util::error::Code; 60 using util::error::INTERNAL; 61 } 62 namespace converter { 63 64 using google::protobuf::Descriptor; 65 using google::protobuf::EnumValueDescriptor; 66 using google::protobuf::FieldDescriptor; 67 using google::protobuf::internal::WireFormat; 68 using google::protobuf::internal::WireFormatLite; 69 using util::Status; 70 using util::StatusOr; 71 72 namespace { 73 74 static int kDefaultMaxRecursionDepth = 64; 75 76 // Finds a field with the given number. NULL if none found. 77 const google::protobuf::Field* FindFieldByNumber( 78 const google::protobuf::Type& type, int number); 79 80 // Returns true if the field is packable. 81 bool IsPackable(const google::protobuf::Field& field); 82 83 // Finds an enum value with the given number. NULL if none found. 84 const google::protobuf::EnumValue* FindEnumValueByNumber( 85 const google::protobuf::Enum& tech_enum, int number); 86 87 // Utility function to format nanos. 88 const string FormatNanos(uint32 nanos); 89 90 StatusOr<string> MapKeyDefaultValueAsString( 91 const google::protobuf::Field& field) { 92 switch (field.kind()) { 93 case google::protobuf::Field_Kind_TYPE_BOOL: 94 return string("false"); 95 case google::protobuf::Field_Kind_TYPE_INT32: 96 case google::protobuf::Field_Kind_TYPE_INT64: 97 case google::protobuf::Field_Kind_TYPE_UINT32: 98 case google::protobuf::Field_Kind_TYPE_UINT64: 99 case google::protobuf::Field_Kind_TYPE_SINT32: 100 case google::protobuf::Field_Kind_TYPE_SINT64: 101 case google::protobuf::Field_Kind_TYPE_SFIXED32: 102 case google::protobuf::Field_Kind_TYPE_SFIXED64: 103 case google::protobuf::Field_Kind_TYPE_FIXED32: 104 case google::protobuf::Field_Kind_TYPE_FIXED64: 105 return string("0"); 106 case google::protobuf::Field_Kind_TYPE_STRING: 107 return string(); 108 default: 109 return Status(util::error::INTERNAL, "Invalid map key type."); 110 } 111 } 112 } // namespace 113 114 115 ProtoStreamObjectSource::ProtoStreamObjectSource( 116 google::protobuf::io::CodedInputStream* stream, TypeResolver* type_resolver, 117 const google::protobuf::Type& type) 118 : stream_(stream), 119 typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), 120 own_typeinfo_(true), 121 type_(type), 122 use_lower_camel_for_enums_(false), 123 recursion_depth_(0), 124 max_recursion_depth_(kDefaultMaxRecursionDepth) { 125 GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL."; 126 } 127 128 ProtoStreamObjectSource::ProtoStreamObjectSource( 129 google::protobuf::io::CodedInputStream* stream, const TypeInfo* typeinfo, 130 const google::protobuf::Type& type) 131 : stream_(stream), 132 typeinfo_(typeinfo), 133 own_typeinfo_(false), 134 type_(type), 135 use_lower_camel_for_enums_(false), 136 recursion_depth_(0), 137 max_recursion_depth_(kDefaultMaxRecursionDepth) { 138 GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL."; 139 } 140 141 ProtoStreamObjectSource::~ProtoStreamObjectSource() { 142 if (own_typeinfo_) { 143 delete typeinfo_; 144 } 145 } 146 147 Status ProtoStreamObjectSource::NamedWriteTo(StringPiece name, 148 ObjectWriter* ow) const { 149 return WriteMessage(type_, name, 0, true, ow); 150 } 151 152 const google::protobuf::Field* ProtoStreamObjectSource::FindAndVerifyField( 153 const google::protobuf::Type& type, uint32 tag) const { 154 // Lookup the new field in the type by tag number. 155 const google::protobuf::Field* field = FindFieldByNumber(type, tag >> 3); 156 // Verify if the field corresponds to the wire type in tag. 157 // If there is any discrepancy, mark the field as not found. 158 if (field != NULL) { 159 WireFormatLite::WireType expected_type = 160 WireFormatLite::WireTypeForFieldType( 161 static_cast<WireFormatLite::FieldType>(field->kind())); 162 WireFormatLite::WireType actual_type = WireFormatLite::GetTagWireType(tag); 163 if (actual_type != expected_type && 164 (!IsPackable(*field) || 165 actual_type != WireFormatLite::WIRETYPE_LENGTH_DELIMITED)) { 166 field = NULL; 167 } 168 } 169 return field; 170 } 171 172 Status ProtoStreamObjectSource::WriteMessage(const google::protobuf::Type& type, 173 StringPiece name, 174 const uint32 end_tag, 175 bool include_start_and_end, 176 ObjectWriter* ow) const { 177 178 const TypeRenderer* type_renderer = FindTypeRenderer(type.name()); 179 if (type_renderer != NULL) { 180 return (*type_renderer)(this, type, name, ow); 181 } 182 183 const google::protobuf::Field* field = NULL; 184 string field_name; 185 // last_tag set to dummy value that is different from tag. 186 uint32 tag = stream_->ReadTag(), last_tag = tag + 1; 187 188 if (include_start_and_end) { 189 ow->StartObject(name); 190 } 191 while (tag != end_tag) { 192 if (tag != last_tag) { // Update field only if tag is changed. 193 last_tag = tag; 194 field = FindAndVerifyField(type, tag); 195 if (field != NULL) { 196 field_name = field->json_name(); 197 } 198 } 199 if (field == NULL) { 200 // If we didn't find a field, skip this unknown tag. 201 // TODO(wpoon): Check return boolean value. 202 WireFormat::SkipField(stream_, tag, NULL); 203 tag = stream_->ReadTag(); 204 continue; 205 } 206 207 if (field->cardinality() == 208 google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) { 209 bool check_maps = true; 210 211 if (check_maps && IsMap(*field)) { 212 ow->StartObject(field_name); 213 ASSIGN_OR_RETURN(tag, RenderMap(field, field_name, tag, ow)); 214 ow->EndObject(); 215 } else { 216 ASSIGN_OR_RETURN(tag, RenderList(field, field_name, tag, ow)); 217 } 218 } else { 219 // Render the field. 220 RETURN_IF_ERROR(RenderField(field, field_name, ow)); 221 tag = stream_->ReadTag(); 222 } 223 } 224 if (include_start_and_end) { 225 ow->EndObject(); 226 } 227 return Status::OK; 228 } 229 230 StatusOr<uint32> ProtoStreamObjectSource::RenderList( 231 const google::protobuf::Field* field, StringPiece name, uint32 list_tag, 232 ObjectWriter* ow) const { 233 uint32 tag_to_return = 0; 234 ow->StartList(name); 235 if (IsPackable(*field) && 236 list_tag == 237 WireFormatLite::MakeTag(field->number(), 238 WireFormatLite::WIRETYPE_LENGTH_DELIMITED)) { 239 RETURN_IF_ERROR(RenderPacked(field, ow)); 240 // Since packed fields have a single tag, read another tag from stream to 241 // return. 242 tag_to_return = stream_->ReadTag(); 243 } else { 244 do { 245 RETURN_IF_ERROR(RenderField(field, "", ow)); 246 } while ((tag_to_return = stream_->ReadTag()) == list_tag); 247 } 248 ow->EndList(); 249 return tag_to_return; 250 } 251 252 StatusOr<uint32> ProtoStreamObjectSource::RenderMap( 253 const google::protobuf::Field* field, StringPiece name, uint32 list_tag, 254 ObjectWriter* ow) const { 255 const google::protobuf::Type* field_type = 256 typeinfo_->GetTypeByTypeUrl(field->type_url()); 257 uint32 tag_to_return = 0; 258 do { 259 // Render map entry message type. 260 uint32 buffer32; 261 stream_->ReadVarint32(&buffer32); // message length 262 int old_limit = stream_->PushLimit(buffer32); 263 string map_key; 264 for (uint32 tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) { 265 const google::protobuf::Field* field = 266 FindAndVerifyField(*field_type, tag); 267 if (field == NULL) { 268 WireFormat::SkipField(stream_, tag, NULL); 269 continue; 270 } 271 // Map field numbers are key = 1 and value = 2 272 if (field->number() == 1) { 273 map_key = ReadFieldValueAsString(*field); 274 } else if (field->number() == 2) { 275 if (map_key.empty()) { 276 // An absent map key is treated as the default. 277 const google::protobuf::Field* key_field = 278 FindFieldByNumber(*field_type, 1); 279 if (key_field == NULL) { 280 // The Type info for this map entry is incorrect. It should always 281 // have a field named "key" and with field number 1. 282 return Status(util::error::INTERNAL, "Invalid map entry."); 283 } 284 ASSIGN_OR_RETURN(map_key, MapKeyDefaultValueAsString(*key_field)); 285 } 286 RETURN_IF_ERROR(RenderField(field, map_key, ow)); 287 } else { 288 // The Type info for this map entry is incorrect. It should contain 289 // exactly two fields with field number 1 and 2. 290 return Status(util::error::INTERNAL, "Invalid map entry."); 291 } 292 } 293 stream_->PopLimit(old_limit); 294 } while ((tag_to_return = stream_->ReadTag()) == list_tag); 295 return tag_to_return; 296 } 297 298 Status ProtoStreamObjectSource::RenderPacked( 299 const google::protobuf::Field* field, ObjectWriter* ow) const { 300 uint32 length; 301 stream_->ReadVarint32(&length); 302 int old_limit = stream_->PushLimit(length); 303 while (stream_->BytesUntilLimit() > 0) { 304 RETURN_IF_ERROR(RenderField(field, StringPiece(), ow)); 305 } 306 stream_->PopLimit(old_limit); 307 return Status::OK; 308 } 309 310 Status ProtoStreamObjectSource::RenderTimestamp( 311 const ProtoStreamObjectSource* os, const google::protobuf::Type& type, 312 StringPiece field_name, ObjectWriter* ow) { 313 pair<int64, int32> p = os->ReadSecondsAndNanos(type); 314 int64 seconds = p.first; 315 int32 nanos = p.second; 316 if (seconds > kTimestampMaxSeconds || seconds < kTimestampMinSeconds) { 317 return Status( 318 util::error::INTERNAL, 319 StrCat("Timestamp seconds exceeds limit for field: ", field_name)); 320 } 321 322 if (nanos < 0 || nanos >= kNanosPerSecond) { 323 return Status( 324 util::error::INTERNAL, 325 StrCat("Timestamp nanos exceeds limit for field: ", field_name)); 326 } 327 328 ow->RenderString(field_name, 329 ::google::protobuf::internal::FormatTime(seconds, nanos)); 330 331 return Status::OK; 332 } 333 334 Status ProtoStreamObjectSource::RenderDuration( 335 const ProtoStreamObjectSource* os, const google::protobuf::Type& type, 336 StringPiece field_name, ObjectWriter* ow) { 337 pair<int64, int32> p = os->ReadSecondsAndNanos(type); 338 int64 seconds = p.first; 339 int32 nanos = p.second; 340 if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds) { 341 return Status( 342 util::error::INTERNAL, 343 StrCat("Duration seconds exceeds limit for field: ", field_name)); 344 } 345 346 if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) { 347 return Status( 348 util::error::INTERNAL, 349 StrCat("Duration nanos exceeds limit for field: ", field_name)); 350 } 351 352 string sign = ""; 353 if (seconds < 0) { 354 if (nanos > 0) { 355 return Status(util::error::INTERNAL, 356 StrCat("Duration nanos is non-negative, but seconds is " 357 "negative for field: ", 358 field_name)); 359 } 360 sign = "-"; 361 seconds = -seconds; 362 nanos = -nanos; 363 } else if (seconds == 0 && nanos < 0) { 364 sign = "-"; 365 nanos = -nanos; 366 } 367 string formatted_duration = StringPrintf("%s%lld%ss", sign.c_str(), seconds, 368 FormatNanos(nanos).c_str()); 369 ow->RenderString(field_name, formatted_duration); 370 return Status::OK; 371 } 372 373 Status ProtoStreamObjectSource::RenderDouble(const ProtoStreamObjectSource* os, 374 const google::protobuf::Type& type, 375 StringPiece field_name, 376 ObjectWriter* ow) { 377 uint32 tag = os->stream_->ReadTag(); 378 uint64 buffer64 = 0; // default value of Double wrapper value 379 if (tag != 0) { 380 os->stream_->ReadLittleEndian64(&buffer64); 381 os->stream_->ReadTag(); 382 } 383 ow->RenderDouble(field_name, bit_cast<double>(buffer64)); 384 return Status::OK; 385 } 386 387 Status ProtoStreamObjectSource::RenderFloat(const ProtoStreamObjectSource* os, 388 const google::protobuf::Type& type, 389 StringPiece field_name, 390 ObjectWriter* ow) { 391 uint32 tag = os->stream_->ReadTag(); 392 uint32 buffer32 = 0; // default value of Float wrapper value 393 if (tag != 0) { 394 os->stream_->ReadLittleEndian32(&buffer32); 395 os->stream_->ReadTag(); 396 } 397 ow->RenderFloat(field_name, bit_cast<float>(buffer32)); 398 return Status::OK; 399 } 400 401 Status ProtoStreamObjectSource::RenderInt64(const ProtoStreamObjectSource* os, 402 const google::protobuf::Type& type, 403 StringPiece field_name, 404 ObjectWriter* ow) { 405 uint32 tag = os->stream_->ReadTag(); 406 uint64 buffer64 = 0; // default value of Int64 wrapper value 407 if (tag != 0) { 408 os->stream_->ReadVarint64(&buffer64); 409 os->stream_->ReadTag(); 410 } 411 ow->RenderInt64(field_name, bit_cast<int64>(buffer64)); 412 return Status::OK; 413 } 414 415 Status ProtoStreamObjectSource::RenderUInt64(const ProtoStreamObjectSource* os, 416 const google::protobuf::Type& type, 417 StringPiece field_name, 418 ObjectWriter* ow) { 419 uint32 tag = os->stream_->ReadTag(); 420 uint64 buffer64 = 0; // default value of UInt64 wrapper value 421 if (tag != 0) { 422 os->stream_->ReadVarint64(&buffer64); 423 os->stream_->ReadTag(); 424 } 425 ow->RenderUint64(field_name, bit_cast<uint64>(buffer64)); 426 return Status::OK; 427 } 428 429 Status ProtoStreamObjectSource::RenderInt32(const ProtoStreamObjectSource* os, 430 const google::protobuf::Type& type, 431 StringPiece field_name, 432 ObjectWriter* ow) { 433 uint32 tag = os->stream_->ReadTag(); 434 uint32 buffer32 = 0; // default value of Int32 wrapper value 435 if (tag != 0) { 436 os->stream_->ReadVarint32(&buffer32); 437 os->stream_->ReadTag(); 438 } 439 ow->RenderInt32(field_name, bit_cast<int32>(buffer32)); 440 return Status::OK; 441 } 442 443 Status ProtoStreamObjectSource::RenderUInt32(const ProtoStreamObjectSource* os, 444 const google::protobuf::Type& type, 445 StringPiece field_name, 446 ObjectWriter* ow) { 447 uint32 tag = os->stream_->ReadTag(); 448 uint32 buffer32 = 0; // default value of UInt32 wrapper value 449 if (tag != 0) { 450 os->stream_->ReadVarint32(&buffer32); 451 os->stream_->ReadTag(); 452 } 453 ow->RenderUint32(field_name, bit_cast<uint32>(buffer32)); 454 return Status::OK; 455 } 456 457 Status ProtoStreamObjectSource::RenderBool(const ProtoStreamObjectSource* os, 458 const google::protobuf::Type& type, 459 StringPiece field_name, 460 ObjectWriter* ow) { 461 uint32 tag = os->stream_->ReadTag(); 462 uint64 buffer64 = 0; // results in 'false' value as default, which is the 463 // default value of Bool wrapper 464 if (tag != 0) { 465 os->stream_->ReadVarint64(&buffer64); 466 os->stream_->ReadTag(); 467 } 468 ow->RenderBool(field_name, buffer64 != 0); 469 return Status::OK; 470 } 471 472 Status ProtoStreamObjectSource::RenderString(const ProtoStreamObjectSource* os, 473 const google::protobuf::Type& type, 474 StringPiece field_name, 475 ObjectWriter* ow) { 476 uint32 tag = os->stream_->ReadTag(); 477 uint32 buffer32; 478 string str; // default value of empty for String wrapper 479 if (tag != 0) { 480 os->stream_->ReadVarint32(&buffer32); // string size. 481 os->stream_->ReadString(&str, buffer32); 482 os->stream_->ReadTag(); 483 } 484 ow->RenderString(field_name, str); 485 return Status::OK; 486 } 487 488 Status ProtoStreamObjectSource::RenderBytes(const ProtoStreamObjectSource* os, 489 const google::protobuf::Type& type, 490 StringPiece field_name, 491 ObjectWriter* ow) { 492 uint32 tag = os->stream_->ReadTag(); 493 uint32 buffer32; 494 string str; 495 if (tag != 0) { 496 os->stream_->ReadVarint32(&buffer32); 497 os->stream_->ReadString(&str, buffer32); 498 os->stream_->ReadTag(); 499 } 500 ow->RenderBytes(field_name, str); 501 return Status::OK; 502 } 503 504 Status ProtoStreamObjectSource::RenderStruct(const ProtoStreamObjectSource* os, 505 const google::protobuf::Type& type, 506 StringPiece field_name, 507 ObjectWriter* ow) { 508 const google::protobuf::Field* field = NULL; 509 uint32 tag = os->stream_->ReadTag(); 510 ow->StartObject(field_name); 511 while (tag != 0) { 512 field = os->FindAndVerifyField(type, tag); 513 // google.protobuf.Struct has only one field that is a map. Hence we use 514 // RenderMap to render that field. 515 if (os->IsMap(*field)) { 516 ASSIGN_OR_RETURN(tag, os->RenderMap(field, field_name, tag, ow)); 517 } 518 } 519 ow->EndObject(); 520 return Status::OK; 521 } 522 523 Status ProtoStreamObjectSource::RenderStructValue( 524 const ProtoStreamObjectSource* os, const google::protobuf::Type& type, 525 StringPiece field_name, ObjectWriter* ow) { 526 const google::protobuf::Field* field = NULL; 527 for (uint32 tag = os->stream_->ReadTag(); tag != 0; 528 tag = os->stream_->ReadTag()) { 529 field = os->FindAndVerifyField(type, tag); 530 if (field == NULL) { 531 WireFormat::SkipField(os->stream_, tag, NULL); 532 continue; 533 } 534 RETURN_IF_ERROR(os->RenderField(field, field_name, ow)); 535 } 536 return Status::OK; 537 } 538 539 // TODO(skarvaje): Avoid code duplication of for loops and SkipField logic. 540 Status ProtoStreamObjectSource::RenderStructListValue( 541 const ProtoStreamObjectSource* os, const google::protobuf::Type& type, 542 StringPiece field_name, ObjectWriter* ow) { 543 uint32 tag = os->stream_->ReadTag(); 544 545 // Render empty list when we find empty ListValue message. 546 if (tag == 0) { 547 ow->StartList(field_name); 548 ow->EndList(); 549 return Status::OK; 550 } 551 552 while (tag != 0) { 553 const google::protobuf::Field* field = os->FindAndVerifyField(type, tag); 554 if (field == NULL) { 555 WireFormat::SkipField(os->stream_, tag, NULL); 556 tag = os->stream_->ReadTag(); 557 continue; 558 } 559 ASSIGN_OR_RETURN(tag, os->RenderList(field, field_name, tag, ow)); 560 } 561 return Status::OK; 562 } 563 564 Status ProtoStreamObjectSource::RenderAny(const ProtoStreamObjectSource* os, 565 const google::protobuf::Type& type, 566 StringPiece field_name, 567 ObjectWriter* ow) { 568 // An Any is of the form { string type_url = 1; bytes value = 2; } 569 uint32 tag; 570 string type_url; 571 string value; 572 573 // First read out the type_url and value from the proto stream 574 for (tag = os->stream_->ReadTag(); tag != 0; tag = os->stream_->ReadTag()) { 575 const google::protobuf::Field* field = os->FindAndVerifyField(type, tag); 576 if (field == NULL) { 577 WireFormat::SkipField(os->stream_, tag, NULL); 578 continue; 579 } 580 // 'type_url' has field number of 1 and 'value' has field number 2 581 // //google/protobuf/any.proto 582 if (field->number() == 1) { 583 // read type_url 584 uint32 type_url_size; 585 os->stream_->ReadVarint32(&type_url_size); 586 os->stream_->ReadString(&type_url, type_url_size); 587 } else if (field->number() == 2) { 588 // read value 589 uint32 value_size; 590 os->stream_->ReadVarint32(&value_size); 591 os->stream_->ReadString(&value, value_size); 592 } 593 } 594 595 // If there is no value, we don't lookup the type, we just output it (if 596 // present). If both type and value are empty we output an empty object. 597 if (value.empty()) { 598 ow->StartObject(field_name); 599 if (!type_url.empty()) { 600 ow->RenderString("@type", type_url); 601 } 602 ow->EndObject(); 603 return util::Status::OK; 604 } 605 606 // If there is a value but no type, we cannot render it, so report an error. 607 if (type_url.empty()) { 608 // TODO(sven): Add an external message once those are ready. 609 return util::Status(util::error::INTERNAL, 610 "Invalid Any, the type_url is missing."); 611 } 612 613 util::StatusOr<const google::protobuf::Type*> resolved_type = 614 os->typeinfo_->ResolveTypeUrl(type_url); 615 616 if (!resolved_type.ok()) { 617 // Convert into an internal error, since this means the backend gave us 618 // an invalid response (missing or invalid type information). 619 return util::Status(util::error::INTERNAL, 620 resolved_type.status().error_message()); 621 } 622 // nested_type cannot be null at this time. 623 const google::protobuf::Type* nested_type = resolved_type.ValueOrDie(); 624 625 google::protobuf::io::ArrayInputStream zero_copy_stream(value.data(), value.size()); 626 google::protobuf::io::CodedInputStream in_stream(&zero_copy_stream); 627 // We know the type so we can render it. Recursively parse the nested stream 628 // using a nested ProtoStreamObjectSource using our nested type information. 629 ProtoStreamObjectSource nested_os(&in_stream, os->typeinfo_, *nested_type); 630 631 // We manually call start and end object here so we can inject the @type. 632 ow->StartObject(field_name); 633 ow->RenderString("@type", type_url); 634 util::Status result = 635 nested_os.WriteMessage(nested_os.type_, "value", 0, false, ow); 636 ow->EndObject(); 637 return result; 638 } 639 640 Status ProtoStreamObjectSource::RenderFieldMask( 641 const ProtoStreamObjectSource* os, const google::protobuf::Type& type, 642 StringPiece field_name, ObjectWriter* ow) { 643 string combined; 644 uint32 buffer32; 645 uint32 paths_field_tag = 0; 646 for (uint32 tag = os->stream_->ReadTag(); tag != 0; 647 tag = os->stream_->ReadTag()) { 648 if (paths_field_tag == 0) { 649 const google::protobuf::Field* field = os->FindAndVerifyField(type, tag); 650 if (field != NULL && field->number() == 1 && 651 field->name() == "paths") { 652 paths_field_tag = tag; 653 } 654 } 655 if (paths_field_tag != tag) { 656 return util::Status(util::error::INTERNAL, 657 "Invalid FieldMask, unexpected field."); 658 } 659 string str; 660 os->stream_->ReadVarint32(&buffer32); // string size. 661 os->stream_->ReadString(&str, buffer32); 662 if (!combined.empty()) { 663 combined.append(","); 664 } 665 combined.append(ConvertFieldMaskPath(str, &ToCamelCase)); 666 } 667 ow->RenderString(field_name, combined); 668 return Status::OK; 669 } 670 671 672 hash_map<string, ProtoStreamObjectSource::TypeRenderer>* 673 ProtoStreamObjectSource::renderers_ = NULL; 674 GOOGLE_PROTOBUF_DECLARE_ONCE(source_renderers_init_); 675 676 void ProtoStreamObjectSource::InitRendererMap() { 677 renderers_ = new hash_map<string, ProtoStreamObjectSource::TypeRenderer>(); 678 (*renderers_)["google.protobuf.Timestamp"] = 679 &ProtoStreamObjectSource::RenderTimestamp; 680 (*renderers_)["google.protobuf.Duration"] = 681 &ProtoStreamObjectSource::RenderDuration; 682 (*renderers_)["google.protobuf.DoubleValue"] = 683 &ProtoStreamObjectSource::RenderDouble; 684 (*renderers_)["google.protobuf.FloatValue"] = 685 &ProtoStreamObjectSource::RenderFloat; 686 (*renderers_)["google.protobuf.Int64Value"] = 687 &ProtoStreamObjectSource::RenderInt64; 688 (*renderers_)["google.protobuf.UInt64Value"] = 689 &ProtoStreamObjectSource::RenderUInt64; 690 (*renderers_)["google.protobuf.Int32Value"] = 691 &ProtoStreamObjectSource::RenderInt32; 692 (*renderers_)["google.protobuf.UInt32Value"] = 693 &ProtoStreamObjectSource::RenderUInt32; 694 (*renderers_)["google.protobuf.BoolValue"] = 695 &ProtoStreamObjectSource::RenderBool; 696 (*renderers_)["google.protobuf.StringValue"] = 697 &ProtoStreamObjectSource::RenderString; 698 (*renderers_)["google.protobuf.BytesValue"] = 699 &ProtoStreamObjectSource::RenderBytes; 700 (*renderers_)["google.protobuf.Any"] = &ProtoStreamObjectSource::RenderAny; 701 (*renderers_)["google.protobuf.Struct"] = 702 &ProtoStreamObjectSource::RenderStruct; 703 (*renderers_)["google.protobuf.Value"] = 704 &ProtoStreamObjectSource::RenderStructValue; 705 (*renderers_)["google.protobuf.ListValue"] = 706 &ProtoStreamObjectSource::RenderStructListValue; 707 (*renderers_)["google.protobuf.FieldMask"] = 708 &ProtoStreamObjectSource::RenderFieldMask; 709 ::google::protobuf::internal::OnShutdown(&DeleteRendererMap); 710 } 711 712 void ProtoStreamObjectSource::DeleteRendererMap() { 713 delete ProtoStreamObjectSource::renderers_; 714 renderers_ = NULL; 715 } 716 717 // static 718 ProtoStreamObjectSource::TypeRenderer* 719 ProtoStreamObjectSource::FindTypeRenderer(const string& type_url) { 720 ::google::protobuf::GoogleOnceInit(&source_renderers_init_, &InitRendererMap); 721 return FindOrNull(*renderers_, type_url); 722 } 723 724 Status ProtoStreamObjectSource::RenderField( 725 const google::protobuf::Field* field, StringPiece field_name, 726 ObjectWriter* ow) const { 727 // Short-circuit message types as it tends to call WriteMessage recursively 728 // and ends up using a lot of stack space. Keep the stack usage of this 729 // message small in order to preserve stack space and not crash. 730 if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) { 731 uint32 buffer32; 732 stream_->ReadVarint32(&buffer32); // message length 733 int old_limit = stream_->PushLimit(buffer32); 734 // Get the nested message type for this field. 735 const google::protobuf::Type* type = 736 typeinfo_->GetTypeByTypeUrl(field->type_url()); 737 if (type == NULL) { 738 return Status(util::error::INTERNAL, 739 StrCat("Invalid configuration. Could not find the type: ", 740 field->type_url())); 741 } 742 743 // Short-circuit any special type rendering to save call-stack space. 744 const TypeRenderer* type_renderer = FindTypeRenderer(type->name()); 745 746 bool use_type_renderer = type_renderer != NULL; 747 748 if (use_type_renderer) { 749 RETURN_IF_ERROR((*type_renderer)(this, *type, field_name, ow)); 750 } else { 751 RETURN_IF_ERROR(IncrementRecursionDepth(type->name(), field_name)); 752 RETURN_IF_ERROR(WriteMessage(*type, field_name, 0, true, ow)); 753 --recursion_depth_; 754 } 755 if (!stream_->ConsumedEntireMessage()) { 756 return Status(util::error::INVALID_ARGUMENT, 757 "Nested protocol message not parsed in its entirety."); 758 } 759 stream_->PopLimit(old_limit); 760 } else { 761 // Render all other non-message types. 762 return RenderNonMessageField(field, field_name, ow); 763 } 764 return Status::OK; 765 } 766 767 Status ProtoStreamObjectSource::RenderNonMessageField( 768 const google::protobuf::Field* field, StringPiece field_name, 769 ObjectWriter* ow) const { 770 // Temporary buffers of different types. 771 uint32 buffer32; 772 uint64 buffer64; 773 string strbuffer; 774 switch (field->kind()) { 775 case google::protobuf::Field_Kind_TYPE_BOOL: { 776 stream_->ReadVarint64(&buffer64); 777 ow->RenderBool(field_name, buffer64 != 0); 778 break; 779 } 780 case google::protobuf::Field_Kind_TYPE_INT32: { 781 stream_->ReadVarint32(&buffer32); 782 ow->RenderInt32(field_name, bit_cast<int32>(buffer32)); 783 break; 784 } 785 case google::protobuf::Field_Kind_TYPE_INT64: { 786 stream_->ReadVarint64(&buffer64); 787 ow->RenderInt64(field_name, bit_cast<int64>(buffer64)); 788 break; 789 } 790 case google::protobuf::Field_Kind_TYPE_UINT32: { 791 stream_->ReadVarint32(&buffer32); 792 ow->RenderUint32(field_name, bit_cast<uint32>(buffer32)); 793 break; 794 } 795 case google::protobuf::Field_Kind_TYPE_UINT64: { 796 stream_->ReadVarint64(&buffer64); 797 ow->RenderUint64(field_name, bit_cast<uint64>(buffer64)); 798 break; 799 } 800 case google::protobuf::Field_Kind_TYPE_SINT32: { 801 stream_->ReadVarint32(&buffer32); 802 ow->RenderInt32(field_name, WireFormatLite::ZigZagDecode32(buffer32)); 803 break; 804 } 805 case google::protobuf::Field_Kind_TYPE_SINT64: { 806 stream_->ReadVarint64(&buffer64); 807 ow->RenderInt64(field_name, WireFormatLite::ZigZagDecode64(buffer64)); 808 break; 809 } 810 case google::protobuf::Field_Kind_TYPE_SFIXED32: { 811 stream_->ReadLittleEndian32(&buffer32); 812 ow->RenderInt32(field_name, bit_cast<int32>(buffer32)); 813 break; 814 } 815 case google::protobuf::Field_Kind_TYPE_SFIXED64: { 816 stream_->ReadLittleEndian64(&buffer64); 817 ow->RenderInt64(field_name, bit_cast<int64>(buffer64)); 818 break; 819 } 820 case google::protobuf::Field_Kind_TYPE_FIXED32: { 821 stream_->ReadLittleEndian32(&buffer32); 822 ow->RenderUint32(field_name, bit_cast<uint32>(buffer32)); 823 break; 824 } 825 case google::protobuf::Field_Kind_TYPE_FIXED64: { 826 stream_->ReadLittleEndian64(&buffer64); 827 ow->RenderUint64(field_name, bit_cast<uint64>(buffer64)); 828 break; 829 } 830 case google::protobuf::Field_Kind_TYPE_FLOAT: { 831 stream_->ReadLittleEndian32(&buffer32); 832 ow->RenderFloat(field_name, bit_cast<float>(buffer32)); 833 break; 834 } 835 case google::protobuf::Field_Kind_TYPE_DOUBLE: { 836 stream_->ReadLittleEndian64(&buffer64); 837 ow->RenderDouble(field_name, bit_cast<double>(buffer64)); 838 break; 839 } 840 case google::protobuf::Field_Kind_TYPE_ENUM: { 841 stream_->ReadVarint32(&buffer32); 842 843 // If the field represents an explicit NULL value, render null. 844 if (field->type_url() == kStructNullValueTypeUrl) { 845 ow->RenderNull(field_name); 846 break; 847 } 848 849 // Get the nested enum type for this field. 850 // TODO(skarvaje): Avoid string manipulation. Find ways to speed this 851 // up. 852 const google::protobuf::Enum* en = 853 typeinfo_->GetEnumByTypeUrl(field->type_url()); 854 // Lookup the name of the enum, and render that. Skips unknown enums. 855 if (en != NULL) { 856 const google::protobuf::EnumValue* enum_value = 857 FindEnumValueByNumber(*en, buffer32); 858 if (enum_value != NULL) { 859 if (use_lower_camel_for_enums_) 860 ow->RenderString(field_name, ToCamelCase(enum_value->name())); 861 else 862 ow->RenderString(field_name, enum_value->name()); 863 } 864 } else { 865 GOOGLE_LOG(INFO) << "Unknown enum skipped: " << field->type_url(); 866 } 867 break; 868 } 869 case google::protobuf::Field_Kind_TYPE_STRING: { 870 stream_->ReadVarint32(&buffer32); // string size. 871 stream_->ReadString(&strbuffer, buffer32); 872 ow->RenderString(field_name, strbuffer); 873 break; 874 } 875 case google::protobuf::Field_Kind_TYPE_BYTES: { 876 stream_->ReadVarint32(&buffer32); // bytes size. 877 stream_->ReadString(&strbuffer, buffer32); 878 ow->RenderBytes(field_name, strbuffer); 879 break; 880 } 881 default: 882 break; 883 } 884 return Status::OK; 885 } 886 887 // TODO(skarvaje): Fix this to avoid code duplication. 888 const string ProtoStreamObjectSource::ReadFieldValueAsString( 889 const google::protobuf::Field& field) const { 890 string result; 891 switch (field.kind()) { 892 case google::protobuf::Field_Kind_TYPE_BOOL: { 893 uint64 buffer64; 894 stream_->ReadVarint64(&buffer64); 895 result = buffer64 != 0 ? "true" : "false"; 896 break; 897 } 898 case google::protobuf::Field_Kind_TYPE_INT32: { 899 uint32 buffer32; 900 stream_->ReadVarint32(&buffer32); 901 result = SimpleItoa(bit_cast<int32>(buffer32)); 902 break; 903 } 904 case google::protobuf::Field_Kind_TYPE_INT64: { 905 uint64 buffer64; 906 stream_->ReadVarint64(&buffer64); 907 result = SimpleItoa(bit_cast<int64>(buffer64)); 908 break; 909 } 910 case google::protobuf::Field_Kind_TYPE_UINT32: { 911 uint32 buffer32; 912 stream_->ReadVarint32(&buffer32); 913 result = SimpleItoa(bit_cast<uint32>(buffer32)); 914 break; 915 } 916 case google::protobuf::Field_Kind_TYPE_UINT64: { 917 uint64 buffer64; 918 stream_->ReadVarint64(&buffer64); 919 result = SimpleItoa(bit_cast<uint64>(buffer64)); 920 break; 921 } 922 case google::protobuf::Field_Kind_TYPE_SINT32: { 923 uint32 buffer32; 924 stream_->ReadVarint32(&buffer32); 925 result = SimpleItoa(WireFormatLite::ZigZagDecode32(buffer32)); 926 break; 927 } 928 case google::protobuf::Field_Kind_TYPE_SINT64: { 929 uint64 buffer64; 930 stream_->ReadVarint64(&buffer64); 931 result = SimpleItoa(WireFormatLite::ZigZagDecode64(buffer64)); 932 break; 933 } 934 case google::protobuf::Field_Kind_TYPE_SFIXED32: { 935 uint32 buffer32; 936 stream_->ReadLittleEndian32(&buffer32); 937 result = SimpleItoa(bit_cast<int32>(buffer32)); 938 break; 939 } 940 case google::protobuf::Field_Kind_TYPE_SFIXED64: { 941 uint64 buffer64; 942 stream_->ReadLittleEndian64(&buffer64); 943 result = SimpleItoa(bit_cast<int64>(buffer64)); 944 break; 945 } 946 case google::protobuf::Field_Kind_TYPE_FIXED32: { 947 uint32 buffer32; 948 stream_->ReadLittleEndian32(&buffer32); 949 result = SimpleItoa(bit_cast<uint32>(buffer32)); 950 break; 951 } 952 case google::protobuf::Field_Kind_TYPE_FIXED64: { 953 uint64 buffer64; 954 stream_->ReadLittleEndian64(&buffer64); 955 result = SimpleItoa(bit_cast<uint64>(buffer64)); 956 break; 957 } 958 case google::protobuf::Field_Kind_TYPE_FLOAT: { 959 uint32 buffer32; 960 stream_->ReadLittleEndian32(&buffer32); 961 result = SimpleFtoa(bit_cast<float>(buffer32)); 962 break; 963 } 964 case google::protobuf::Field_Kind_TYPE_DOUBLE: { 965 uint64 buffer64; 966 stream_->ReadLittleEndian64(&buffer64); 967 result = SimpleDtoa(bit_cast<double>(buffer64)); 968 break; 969 } 970 case google::protobuf::Field_Kind_TYPE_ENUM: { 971 uint32 buffer32; 972 stream_->ReadVarint32(&buffer32); 973 // Get the nested enum type for this field. 974 // TODO(skarvaje): Avoid string manipulation. Find ways to speed this 975 // up. 976 const google::protobuf::Enum* en = 977 typeinfo_->GetEnumByTypeUrl(field.type_url()); 978 // Lookup the name of the enum, and render that. Skips unknown enums. 979 if (en != NULL) { 980 const google::protobuf::EnumValue* enum_value = 981 FindEnumValueByNumber(*en, buffer32); 982 if (enum_value != NULL) { 983 result = enum_value->name(); 984 } 985 } 986 break; 987 } 988 case google::protobuf::Field_Kind_TYPE_STRING: { 989 uint32 buffer32; 990 stream_->ReadVarint32(&buffer32); // string size. 991 stream_->ReadString(&result, buffer32); 992 break; 993 } 994 case google::protobuf::Field_Kind_TYPE_BYTES: { 995 uint32 buffer32; 996 stream_->ReadVarint32(&buffer32); // bytes size. 997 stream_->ReadString(&result, buffer32); 998 break; 999 } 1000 default: 1001 break; 1002 } 1003 return result; 1004 } 1005 1006 // Field is a map if it is a repeated message and it has an option "map_type". 1007 // TODO(skarvaje): Consider pre-computing the IsMap() into Field directly. 1008 bool ProtoStreamObjectSource::IsMap( 1009 const google::protobuf::Field& field) const { 1010 const google::protobuf::Type* field_type = 1011 typeinfo_->GetTypeByTypeUrl(field.type_url()); 1012 1013 // TODO(xiaofeng): Unify option names. 1014 return field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE && 1015 (GetBoolOptionOrDefault(field_type->options(), 1016 "google.protobuf.MessageOptions.map_entry", false) || 1017 GetBoolOptionOrDefault(field_type->options(), "map_entry", false)); 1018 } 1019 1020 std::pair<int64, int32> ProtoStreamObjectSource::ReadSecondsAndNanos( 1021 const google::protobuf::Type& type) const { 1022 uint64 seconds = 0; 1023 uint32 nanos = 0; 1024 uint32 tag = 0; 1025 int64 signed_seconds = 0; 1026 int32 signed_nanos = 0; 1027 1028 for (tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) { 1029 const google::protobuf::Field* field = FindAndVerifyField(type, tag); 1030 if (field == NULL) { 1031 WireFormat::SkipField(stream_, tag, NULL); 1032 continue; 1033 } 1034 // 'seconds' has field number of 1 and 'nanos' has field number 2 1035 // //google/protobuf/timestamp.proto & duration.proto 1036 if (field->number() == 1) { 1037 // read seconds 1038 stream_->ReadVarint64(&seconds); 1039 signed_seconds = bit_cast<int64>(seconds); 1040 } else if (field->number() == 2) { 1041 // read nanos 1042 stream_->ReadVarint32(&nanos); 1043 signed_nanos = bit_cast<int32>(nanos); 1044 } 1045 } 1046 return std::pair<int64, int32>(signed_seconds, signed_nanos); 1047 } 1048 1049 Status ProtoStreamObjectSource::IncrementRecursionDepth( 1050 StringPiece type_name, StringPiece field_name) const { 1051 if (++recursion_depth_ > max_recursion_depth_) { 1052 return Status( 1053 util::error::INVALID_ARGUMENT, 1054 StrCat("Message too deep. Max recursion depth reached for type '", 1055 type_name, "', field '", field_name, "'")); 1056 } 1057 return Status::OK; 1058 } 1059 1060 namespace { 1061 // TODO(skarvaje): Speed this up by not doing a linear scan. 1062 const google::protobuf::Field* FindFieldByNumber( 1063 const google::protobuf::Type& type, int number) { 1064 for (int i = 0; i < type.fields_size(); ++i) { 1065 if (type.fields(i).number() == number) { 1066 return &type.fields(i); 1067 } 1068 } 1069 return NULL; 1070 } 1071 1072 // TODO(skarvaje): Replace FieldDescriptor by implementing IsTypePackable() 1073 // using tech Field. 1074 bool IsPackable(const google::protobuf::Field& field) { 1075 return field.cardinality() == 1076 google::protobuf::Field_Cardinality_CARDINALITY_REPEATED && 1077 google::protobuf::FieldDescriptor::IsTypePackable( 1078 static_cast<google::protobuf::FieldDescriptor::Type>(field.kind())); 1079 } 1080 1081 // TODO(skarvaje): Speed this up by not doing a linear scan. 1082 const google::protobuf::EnumValue* FindEnumValueByNumber( 1083 const google::protobuf::Enum& tech_enum, int number) { 1084 for (int i = 0; i < tech_enum.enumvalue_size(); ++i) { 1085 const google::protobuf::EnumValue& ev = tech_enum.enumvalue(i); 1086 if (ev.number() == number) { 1087 return &ev; 1088 } 1089 } 1090 return NULL; 1091 } 1092 1093 // TODO(skarvaje): Look into optimizing this by not doing computation on 1094 // double. 1095 const string FormatNanos(uint32 nanos) { 1096 const char* format = 1097 (nanos % 1000 != 0) ? "%.9f" : (nanos % 1000000 != 0) ? "%.6f" : "%.3f"; 1098 string formatted = 1099 StringPrintf(format, static_cast<double>(nanos) / kNanosPerSecond); 1100 // remove the leading 0 before decimal. 1101 return formatted.substr(1); 1102 } 1103 } // namespace 1104 1105 } // namespace converter 1106 } // namespace util 1107 } // namespace protobuf 1108 } // namespace google 1109