| OLD | NEW |
| 1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
| 2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
| 3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
| 4 // | 4 // |
| 5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
| 6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
| 7 // met: | 7 // met: |
| 8 // | 8 // |
| 9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
| 10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 38 #include <memory> | 38 #include <memory> |
| 39 #ifndef _SHARED_PTR_H | 39 #ifndef _SHARED_PTR_H |
| 40 #include <google/protobuf/stubs/shared_ptr.h> | 40 #include <google/protobuf/stubs/shared_ptr.h> |
| 41 #endif | 41 #endif |
| 42 | 42 |
| 43 #include <google/protobuf/stubs/logging.h> | 43 #include <google/protobuf/stubs/logging.h> |
| 44 #include <google/protobuf/stubs/common.h> | 44 #include <google/protobuf/stubs/common.h> |
| 45 #include <google/protobuf/util/internal/object_writer.h> | 45 #include <google/protobuf/util/internal/object_writer.h> |
| 46 #include <google/protobuf/util/internal/json_escaping.h> | 46 #include <google/protobuf/util/internal/json_escaping.h> |
| 47 #include <google/protobuf/stubs/strutil.h> | 47 #include <google/protobuf/stubs/strutil.h> |
| 48 #include <google/protobuf/stubs/mathlimits.h> |
| 49 |
| 48 | 50 |
| 49 namespace google { | 51 namespace google { |
| 50 namespace protobuf { | 52 namespace protobuf { |
| 51 namespace util { | 53 namespace util { |
| 52 | 54 |
| 53 // Allow these symbols to be referenced as util::Status, util::error::* in | 55 // Allow these symbols to be referenced as util::Status, util::error::* in |
| 54 // this file. | 56 // this file. |
| 55 using util::Status; | 57 using util::Status; |
| 56 namespace error { | 58 namespace error { |
| 57 using util::error::INTERNAL; | 59 using util::error::INTERNAL; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 leftover_(), | 102 leftover_(), |
| 101 json_(), | 103 json_(), |
| 102 p_(), | 104 p_(), |
| 103 key_(), | 105 key_(), |
| 104 key_storage_(), | 106 key_storage_(), |
| 105 finishing_(false), | 107 finishing_(false), |
| 106 parsed_(), | 108 parsed_(), |
| 107 parsed_storage_(), | 109 parsed_storage_(), |
| 108 string_open_(0), | 110 string_open_(0), |
| 109 chunk_storage_(), | 111 chunk_storage_(), |
| 110 coerce_to_utf8_(false) { | 112 coerce_to_utf8_(false), |
| 113 allow_empty_null_(false), |
| 114 loose_float_number_conversion_(false) { |
| 111 // Initialize the stack with a single value to be parsed. | 115 // Initialize the stack with a single value to be parsed. |
| 112 stack_.push(VALUE); | 116 stack_.push(VALUE); |
| 113 } | 117 } |
| 114 | 118 |
| 115 JsonStreamParser::~JsonStreamParser() {} | 119 JsonStreamParser::~JsonStreamParser() {} |
| 116 | 120 |
| 117 | 121 |
| 118 util::Status JsonStreamParser::Parse(StringPiece json) { | 122 util::Status JsonStreamParser::Parse(StringPiece json) { |
| 119 StringPiece chunk = json; | 123 StringPiece chunk = json; |
| 120 // If we have leftovers from a previous chunk, append the new chunk to it | 124 // If we have leftovers from a previous chunk, append the new chunk to it |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 270 return ParseNumber(); | 274 return ParseNumber(); |
| 271 case BEGIN_TRUE: | 275 case BEGIN_TRUE: |
| 272 return ParseTrue(); | 276 return ParseTrue(); |
| 273 case BEGIN_FALSE: | 277 case BEGIN_FALSE: |
| 274 return ParseFalse(); | 278 return ParseFalse(); |
| 275 case BEGIN_NULL: | 279 case BEGIN_NULL: |
| 276 return ParseNull(); | 280 return ParseNull(); |
| 277 case UNKNOWN: | 281 case UNKNOWN: |
| 278 return ReportUnknown("Expected a value."); | 282 return ReportUnknown("Expected a value."); |
| 279 default: { | 283 default: { |
| 284 if (allow_empty_null_ && IsEmptyNullAllowed(type)) { |
| 285 return ParseEmptyNull(); |
| 286 } |
| 287 |
| 280 // Special case for having been cut off while parsing, wait for more data. | 288 // Special case for having been cut off while parsing, wait for more data. |
| 281 // This handles things like 'fals' being at the end of the string, we | 289 // This handles things like 'fals' being at the end of the string, we |
| 282 // don't know if the next char would be e, completing it, or something | 290 // don't know if the next char would be e, completing it, or something |
| 283 // else, making it invalid. | 291 // else, making it invalid. |
| 284 if (!finishing_ && p_.length() < false_len) { | 292 if (!finishing_ && p_.length() < false_len) { |
| 285 return util::Status::CANCELLED; | 293 return util::Status::CANCELLED; |
| 286 } | 294 } |
| 287 return ReportFailure("Unexpected token."); | 295 return ReportFailure("Unexpected token."); |
| 288 } | 296 } |
| 289 } | 297 } |
| 290 } | 298 } |
| 291 | 299 |
| 292 util::Status JsonStreamParser::ParseString() { | 300 util::Status JsonStreamParser::ParseString() { |
| 293 util::Status result = ParseStringHelper(); | 301 util::Status result = ParseStringHelper(); |
| 294 if (result.ok()) { | 302 if (result.ok()) { |
| 295 ow_->RenderString(key_, parsed_); | 303 ow_->RenderString(key_, parsed_); |
| 296 key_.clear(); | 304 key_ = StringPiece(); |
| 297 parsed_.clear(); | 305 parsed_ = StringPiece(); |
| 298 parsed_storage_.clear(); | 306 parsed_storage_.clear(); |
| 299 } | 307 } |
| 300 return result; | 308 return result; |
| 301 } | 309 } |
| 302 | 310 |
| 303 util::Status JsonStreamParser::ParseStringHelper() { | 311 util::Status JsonStreamParser::ParseStringHelper() { |
| 304 // If we haven't seen the start quote, grab it and remember it for later. | 312 // If we haven't seen the start quote, grab it and remember it for later. |
| 305 if (string_open_ == 0) { | 313 if (string_open_ == 0) { |
| 306 string_open_ = *p_.data(); | 314 string_open_ = *p_.data(); |
| 307 GOOGLE_DCHECK(string_open_ == '\"' || string_open_ == '\''); | 315 GOOGLE_DCHECK(string_open_ == '\"' || string_open_ == '\''); |
| 308 Advance(); | 316 Advance(); |
| 309 } | 317 } |
| 310 // Track where we last copied data from so we can minimize copying. | 318 // Track where we last copied data from so we can minimize copying. |
| 311 const char* last = p_.data(); | 319 const char* last = p_.data(); |
| 312 while (!p_.empty()) { | 320 while (!p_.empty()) { |
| 313 const char* data = p_.data(); | 321 const char* data = p_.data(); |
| 314 if (*data == '\\') { | 322 if (*data == '\\') { |
| 315 // We're about to handle an escape, copy all bytes from last to data. | 323 // We're about to handle an escape, copy all bytes from last to data. |
| 316 if (last < data) { | 324 if (last < data) { |
| 317 parsed_storage_.append(last, data - last); | 325 parsed_storage_.append(last, data - last); |
| 318 last = data; | |
| 319 } | 326 } |
| 320 // If we ran out of string after the \, cancel or report an error | 327 // If we ran out of string after the \, cancel or report an error |
| 321 // depending on if we expect more data later. | 328 // depending on if we expect more data later. |
| 322 if (p_.length() == 1) { | 329 if (p_.length() == 1) { |
| 323 if (!finishing_) { | 330 if (!finishing_) { |
| 324 return util::Status::CANCELLED; | 331 return util::Status::CANCELLED; |
| 325 } | 332 } |
| 326 return ReportFailure("Closing quote expected in string."); | 333 return ReportFailure("Closing quote expected in string."); |
| 327 } | 334 } |
| 328 // Parse a unicode escape if we found \u in the string. | 335 // Parse a unicode escape if we found \u in the string. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 continue; | 371 continue; |
| 365 } | 372 } |
| 366 // If we found the closing quote note it, advance past it, and return. | 373 // If we found the closing quote note it, advance past it, and return. |
| 367 if (*data == string_open_) { | 374 if (*data == string_open_) { |
| 368 // If we didn't copy anything, reuse the input buffer. | 375 // If we didn't copy anything, reuse the input buffer. |
| 369 if (parsed_storage_.empty()) { | 376 if (parsed_storage_.empty()) { |
| 370 parsed_ = StringPiece(last, data - last); | 377 parsed_ = StringPiece(last, data - last); |
| 371 } else { | 378 } else { |
| 372 if (last < data) { | 379 if (last < data) { |
| 373 parsed_storage_.append(last, data - last); | 380 parsed_storage_.append(last, data - last); |
| 374 last = data; | |
| 375 } | 381 } |
| 376 parsed_ = StringPiece(parsed_storage_); | 382 parsed_ = StringPiece(parsed_storage_); |
| 377 } | 383 } |
| 378 // Clear the quote char so next time we try to parse a string we'll | 384 // Clear the quote char so next time we try to parse a string we'll |
| 379 // start fresh. | 385 // start fresh. |
| 380 string_open_ = 0; | 386 string_open_ = 0; |
| 381 Advance(); | 387 Advance(); |
| 382 return util::Status::OK; | 388 return util::Status::OK; |
| 383 } | 389 } |
| 384 // Normal character, just advance past it. | 390 // Normal character, just advance past it. |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 464 return util::Status::OK; | 470 return util::Status::OK; |
| 465 } | 471 } |
| 466 | 472 |
| 467 util::Status JsonStreamParser::ParseNumber() { | 473 util::Status JsonStreamParser::ParseNumber() { |
| 468 NumberResult number; | 474 NumberResult number; |
| 469 util::Status result = ParseNumberHelper(&number); | 475 util::Status result = ParseNumberHelper(&number); |
| 470 if (result.ok()) { | 476 if (result.ok()) { |
| 471 switch (number.type) { | 477 switch (number.type) { |
| 472 case NumberResult::DOUBLE: | 478 case NumberResult::DOUBLE: |
| 473 ow_->RenderDouble(key_, number.double_val); | 479 ow_->RenderDouble(key_, number.double_val); |
| 474 key_.clear(); | 480 key_ = StringPiece(); |
| 475 break; | 481 break; |
| 476 | 482 |
| 477 case NumberResult::INT: | 483 case NumberResult::INT: |
| 478 ow_->RenderInt64(key_, number.int_val); | 484 ow_->RenderInt64(key_, number.int_val); |
| 479 key_.clear(); | 485 key_ = StringPiece(); |
| 480 break; | 486 break; |
| 481 | 487 |
| 482 case NumberResult::UINT: | 488 case NumberResult::UINT: |
| 483 ow_->RenderUint64(key_, number.uint_val); | 489 ow_->RenderUint64(key_, number.uint_val); |
| 484 key_.clear(); | 490 key_ = StringPiece(); |
| 485 break; | 491 break; |
| 486 | 492 |
| 487 default: | 493 default: |
| 488 return ReportFailure("Unable to parse number."); | 494 return ReportFailure("Unable to parse number."); |
| 489 } | 495 } |
| 490 } | 496 } |
| 491 return result; | 497 return result; |
| 492 } | 498 } |
| 493 | 499 |
| 494 util::Status JsonStreamParser::ParseNumberHelper(NumberResult* result) { | 500 util::Status JsonStreamParser::ParseNumberHelper(NumberResult* result) { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 522 } | 528 } |
| 523 | 529 |
| 524 // Create a string containing just the number, so we can use safe_strtoX | 530 // Create a string containing just the number, so we can use safe_strtoX |
| 525 string number = p_.substr(0, index).ToString(); | 531 string number = p_.substr(0, index).ToString(); |
| 526 | 532 |
| 527 // Floating point number, parse as a double. | 533 // Floating point number, parse as a double. |
| 528 if (floating) { | 534 if (floating) { |
| 529 if (!safe_strtod(number, &result->double_val)) { | 535 if (!safe_strtod(number, &result->double_val)) { |
| 530 return ReportFailure("Unable to parse number."); | 536 return ReportFailure("Unable to parse number."); |
| 531 } | 537 } |
| 538 if (!loose_float_number_conversion_ && |
| 539 !MathLimits<double>::IsFinite(result->double_val)) { |
| 540 return ReportFailure("Number exceeds the range of double."); |
| 541 } |
| 532 result->type = NumberResult::DOUBLE; | 542 result->type = NumberResult::DOUBLE; |
| 533 p_.remove_prefix(index); | 543 p_.remove_prefix(index); |
| 534 return util::Status::OK; | 544 return util::Status::OK; |
| 535 } | 545 } |
| 536 | 546 |
| 537 // Positive non-floating point number, parse as a uint64. | 547 // Positive non-floating point number, parse as a uint64. |
| 538 if (!negative) { | 548 if (!negative) { |
| 539 // Octal/Hex numbers are not valid JSON values. | 549 // Octal/Hex numbers are not valid JSON values. |
| 540 if (number.length() >= 2 && number[0] == '0') { | 550 if (number.length() >= 2 && number[0] == '0') { |
| 541 return ReportFailure("Octal/hex numbers are not valid JSON values."); | 551 return ReportFailure("Octal/hex numbers are not valid JSON values."); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 558 } | 568 } |
| 559 result->type = NumberResult::INT; | 569 result->type = NumberResult::INT; |
| 560 p_.remove_prefix(index); | 570 p_.remove_prefix(index); |
| 561 return util::Status::OK; | 571 return util::Status::OK; |
| 562 } | 572 } |
| 563 | 573 |
| 564 util::Status JsonStreamParser::HandleBeginObject() { | 574 util::Status JsonStreamParser::HandleBeginObject() { |
| 565 GOOGLE_DCHECK_EQ('{', *p_.data()); | 575 GOOGLE_DCHECK_EQ('{', *p_.data()); |
| 566 Advance(); | 576 Advance(); |
| 567 ow_->StartObject(key_); | 577 ow_->StartObject(key_); |
| 568 key_.clear(); | 578 key_ = StringPiece(); |
| 569 stack_.push(ENTRY); | 579 stack_.push(ENTRY); |
| 570 return util::Status::OK; | 580 return util::Status::OK; |
| 571 } | 581 } |
| 572 | 582 |
| 573 util::Status JsonStreamParser::ParseObjectMid(TokenType type) { | 583 util::Status JsonStreamParser::ParseObjectMid(TokenType type) { |
| 574 if (type == UNKNOWN) { | 584 if (type == UNKNOWN) { |
| 575 return ReportUnknown("Expected , or } after key:value pair."); | 585 return ReportUnknown("Expected , or } after key:value pair."); |
| 576 } | 586 } |
| 577 | 587 |
| 578 // Object is complete, advance past the comma and render the EndObject. | 588 // Object is complete, advance past the comma and render the EndObject. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 608 // Key is a string (standard JSON), parse it and store the string. | 618 // Key is a string (standard JSON), parse it and store the string. |
| 609 result = ParseStringHelper(); | 619 result = ParseStringHelper(); |
| 610 if (result.ok()) { | 620 if (result.ok()) { |
| 611 key_storage_.clear(); | 621 key_storage_.clear(); |
| 612 if (!parsed_storage_.empty()) { | 622 if (!parsed_storage_.empty()) { |
| 613 parsed_storage_.swap(key_storage_); | 623 parsed_storage_.swap(key_storage_); |
| 614 key_ = StringPiece(key_storage_); | 624 key_ = StringPiece(key_storage_); |
| 615 } else { | 625 } else { |
| 616 key_ = parsed_; | 626 key_ = parsed_; |
| 617 } | 627 } |
| 618 parsed_.clear(); | 628 parsed_ = StringPiece(); |
| 619 } | 629 } |
| 620 } else if (type == BEGIN_KEY) { | 630 } else if (type == BEGIN_KEY) { |
| 621 // Key is a bare key (back compat), create a StringPiece pointing to it. | 631 // Key is a bare key (back compat), create a StringPiece pointing to it. |
| 622 result = ParseKey(); | 632 result = ParseKey(); |
| 623 } else { | 633 } else { |
| 624 // Unknown key type, report an error. | 634 // Unknown key type, report an error. |
| 625 result = ReportFailure("Expected an object key or }."); | 635 result = ReportFailure("Expected an object key or }."); |
| 626 } | 636 } |
| 627 // On success we next expect an entry mid ':' then an object mid ',' or '}' | 637 // On success we next expect an entry mid ':' then an object mid ',' or '}' |
| 628 if (result.ok()) { | 638 if (result.ok()) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 641 stack_.push(VALUE); | 651 stack_.push(VALUE); |
| 642 return util::Status::OK; | 652 return util::Status::OK; |
| 643 } | 653 } |
| 644 return ReportFailure("Expected : between key:value pair."); | 654 return ReportFailure("Expected : between key:value pair."); |
| 645 } | 655 } |
| 646 | 656 |
| 647 util::Status JsonStreamParser::HandleBeginArray() { | 657 util::Status JsonStreamParser::HandleBeginArray() { |
| 648 GOOGLE_DCHECK_EQ('[', *p_.data()); | 658 GOOGLE_DCHECK_EQ('[', *p_.data()); |
| 649 Advance(); | 659 Advance(); |
| 650 ow_->StartList(key_); | 660 ow_->StartList(key_); |
| 651 key_.clear(); | 661 key_ = StringPiece(); |
| 652 stack_.push(ARRAY_VALUE); | 662 stack_.push(ARRAY_VALUE); |
| 653 return util::Status::OK; | 663 return util::Status::OK; |
| 654 } | 664 } |
| 655 | 665 |
| 656 util::Status JsonStreamParser::ParseArrayValue(TokenType type) { | 666 util::Status JsonStreamParser::ParseArrayValue(TokenType type) { |
| 657 if (type == UNKNOWN) { | 667 if (type == UNKNOWN) { |
| 658 return ReportUnknown("Expected a value or ] within an array."); | 668 return ReportUnknown("Expected a value or ] within an array."); |
| 659 } | 669 } |
| 660 | 670 |
| 661 if (type == END_ARRAY) { | 671 if (type == END_ARRAY) { |
| 662 ow_->EndList(); | 672 ow_->EndList(); |
| 663 Advance(); | 673 Advance(); |
| 664 return util::Status::OK; | 674 return util::Status::OK; |
| 665 } | 675 } |
| 666 | 676 |
| 667 // The ParseValue call may push something onto the stack so we need to make | 677 // The ParseValue call may push something onto the stack so we need to make |
| 668 // sure an ARRAY_MID is after it, so we push it on now. | 678 // sure an ARRAY_MID is after it, so we push it on now. Also, the parsing of |
| 679 // empty-null array value is relying on this ARRAY_MID token. |
| 669 stack_.push(ARRAY_MID); | 680 stack_.push(ARRAY_MID); |
| 670 util::Status result = ParseValue(type); | 681 util::Status result = ParseValue(type); |
| 671 if (result == util::Status::CANCELLED) { | 682 if (result == util::Status::CANCELLED) { |
| 672 // If we were cancelled, pop back off the ARRAY_MID so we don't try to | 683 // If we were cancelled, pop back off the ARRAY_MID so we don't try to |
| 673 // push it on again when we try over. | 684 // push it on again when we try over. |
| 674 stack_.pop(); | 685 stack_.pop(); |
| 675 } | 686 } |
| 676 return result; | 687 return result; |
| 677 } | 688 } |
| 678 | 689 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 692 Advance(); | 703 Advance(); |
| 693 stack_.push(ARRAY_VALUE); | 704 stack_.push(ARRAY_VALUE); |
| 694 return util::Status::OK; | 705 return util::Status::OK; |
| 695 } | 706 } |
| 696 // Illegal token after array value. | 707 // Illegal token after array value. |
| 697 return ReportFailure("Expected , or ] after array value."); | 708 return ReportFailure("Expected , or ] after array value."); |
| 698 } | 709 } |
| 699 | 710 |
| 700 util::Status JsonStreamParser::ParseTrue() { | 711 util::Status JsonStreamParser::ParseTrue() { |
| 701 ow_->RenderBool(key_, true); | 712 ow_->RenderBool(key_, true); |
| 702 key_.clear(); | 713 key_ = StringPiece(); |
| 703 p_.remove_prefix(true_len); | 714 p_.remove_prefix(true_len); |
| 704 return util::Status::OK; | 715 return util::Status::OK; |
| 705 } | 716 } |
| 706 | 717 |
| 707 util::Status JsonStreamParser::ParseFalse() { | 718 util::Status JsonStreamParser::ParseFalse() { |
| 708 ow_->RenderBool(key_, false); | 719 ow_->RenderBool(key_, false); |
| 709 key_.clear(); | 720 key_ = StringPiece(); |
| 710 p_.remove_prefix(false_len); | 721 p_.remove_prefix(false_len); |
| 711 return util::Status::OK; | 722 return util::Status::OK; |
| 712 } | 723 } |
| 713 | 724 |
| 714 util::Status JsonStreamParser::ParseNull() { | 725 util::Status JsonStreamParser::ParseNull() { |
| 715 ow_->RenderNull(key_); | 726 ow_->RenderNull(key_); |
| 716 key_.clear(); | 727 key_ = StringPiece(); |
| 717 p_.remove_prefix(null_len); | 728 p_.remove_prefix(null_len); |
| 718 return util::Status::OK; | 729 return util::Status::OK; |
| 719 } | 730 } |
| 720 | 731 |
| 732 util::Status JsonStreamParser::ParseEmptyNull() { |
| 733 ow_->RenderNull(key_); |
| 734 key_ = StringPiece(); |
| 735 return util::Status::OK; |
| 736 } |
| 737 |
| 738 bool JsonStreamParser::IsEmptyNullAllowed(TokenType type) { |
| 739 if (stack_.empty()) return false; |
| 740 return (stack_.top() == ARRAY_MID && type == VALUE_SEPARATOR) || |
| 741 stack_.top() == OBJ_MID; |
| 742 } |
| 743 |
| 721 util::Status JsonStreamParser::ReportFailure(StringPiece message) { | 744 util::Status JsonStreamParser::ReportFailure(StringPiece message) { |
| 722 static const int kContextLength = 20; | 745 static const int kContextLength = 20; |
| 723 const char* p_start = p_.data(); | 746 const char* p_start = p_.data(); |
| 724 const char* json_start = json_.data(); | 747 const char* json_start = json_.data(); |
| 725 const char* begin = std::max(p_start - kContextLength, json_start); | 748 const char* begin = std::max(p_start - kContextLength, json_start); |
| 726 const char* end = | 749 const char* end = |
| 727 std::min(p_start + kContextLength, json_start + json_.size()); | 750 std::min(p_start + kContextLength, json_start + json_.size()); |
| 728 StringPiece segment(begin, end - begin); | 751 StringPiece segment(begin, end - begin); |
| 729 string location(p_start - begin, ' '); | 752 string location(p_start - begin, ' '); |
| 730 location.push_back('^'); | 753 location.push_back('^'); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 811 // can't parse what we have so far. So we don't report an error and just | 834 // can't parse what we have so far. So we don't report an error and just |
| 812 // return UNKNOWN so we can try again later when we have more data, or if we | 835 // return UNKNOWN so we can try again later when we have more data, or if we |
| 813 // finish and we have leftovers. | 836 // finish and we have leftovers. |
| 814 return UNKNOWN; | 837 return UNKNOWN; |
| 815 } | 838 } |
| 816 | 839 |
| 817 } // namespace converter | 840 } // namespace converter |
| 818 } // namespace util | 841 } // namespace util |
| 819 } // namespace protobuf | 842 } // namespace protobuf |
| 820 } // namespace google | 843 } // namespace google |
| OLD | NEW |