Home | History | Annotate | Download | only in internal
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // https://developers.google.com/protocol-buffers/
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions are
      7 // met:
      8 //
      9 //     * Redistributions of source code must retain the above copyright
     10 // notice, this list of conditions and the following disclaimer.
     11 //     * Redistributions in binary form must reproduce the above
     12 // copyright notice, this list of conditions and the following disclaimer
     13 // in the documentation and/or other materials provided with the
     14 // distribution.
     15 //     * Neither the name of Google Inc. nor the names of its
     16 // contributors may be used to endorse or promote products derived from
     17 // this software without specific prior written permission.
     18 //
     19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 #include <google/protobuf/util/internal/proto_writer.h>
     32 
     33 #include <functional>
     34 #include <stack>
     35 
     36 #include <google/protobuf/stubs/once.h>
     37 #include <google/protobuf/stubs/time.h>
     38 #include <google/protobuf/wire_format_lite.h>
     39 #include <google/protobuf/util/internal/field_mask_utility.h>
     40 #include <google/protobuf/util/internal/object_location_tracker.h>
     41 #include <google/protobuf/util/internal/constants.h>
     42 #include <google/protobuf/util/internal/utility.h>
     43 #include <google/protobuf/stubs/strutil.h>
     44 #include <google/protobuf/stubs/map_util.h>
     45 #include <google/protobuf/stubs/statusor.h>
     46 
     47 
     48 namespace google {
     49 namespace protobuf {
     50 namespace util {
     51 namespace converter {
     52 
     53 using google::protobuf::internal::WireFormatLite;
     54 using google::protobuf::io::CodedOutputStream;
     55 using util::error::INVALID_ARGUMENT;
     56 using util::Status;
     57 using util::StatusOr;
     58 
     59 
     60 ProtoWriter::ProtoWriter(TypeResolver* type_resolver,
     61                          const google::protobuf::Type& type,
     62                          strings::ByteSink* output, ErrorListener* listener)
     63     : master_type_(type),
     64       typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
     65       own_typeinfo_(true),
     66       done_(false),
     67       element_(NULL),
     68       size_insert_(),
     69       output_(output),
     70       buffer_(),
     71       adapter_(&buffer_),
     72       stream_(new CodedOutputStream(&adapter_)),
     73       listener_(listener),
     74       invalid_depth_(0),
     75       tracker_(new ObjectLocationTracker()) {}
     76 
     77 ProtoWriter::ProtoWriter(const TypeInfo* typeinfo,
     78                          const google::protobuf::Type& type,
     79                          strings::ByteSink* output, ErrorListener* listener)
     80     : master_type_(type),
     81       typeinfo_(typeinfo),
     82       own_typeinfo_(false),
     83       done_(false),
     84       element_(NULL),
     85       size_insert_(),
     86       output_(output),
     87       buffer_(),
     88       adapter_(&buffer_),
     89       stream_(new CodedOutputStream(&adapter_)),
     90       listener_(listener),
     91       invalid_depth_(0),
     92       tracker_(new ObjectLocationTracker()) {}
     93 
     94 ProtoWriter::~ProtoWriter() {
     95   if (own_typeinfo_) {
     96     delete typeinfo_;
     97   }
     98   if (element_ == NULL) return;
     99   // Cleanup explicitly in order to avoid destructor stack overflow when input
    100   // is deeply nested.
    101   // Cast to BaseElement to avoid doing additional checks (like missing fields)
    102   // during pop().
    103   google::protobuf::scoped_ptr<BaseElement> element(
    104       static_cast<BaseElement*>(element_.get())->pop<BaseElement>());
    105   while (element != NULL) {
    106     element.reset(element->pop<BaseElement>());
    107   }
    108 }
    109 
    110 namespace {
    111 
    112 // Writes an INT32 field, including tag to the stream.
    113 inline Status WriteInt32(int field_number, const DataPiece& data,
    114                          CodedOutputStream* stream) {
    115   StatusOr<int32> i32 = data.ToInt32();
    116   if (i32.ok()) {
    117     WireFormatLite::WriteInt32(field_number, i32.ValueOrDie(), stream);
    118   }
    119   return i32.status();
    120 }
    121 
    122 // writes an SFIXED32 field, including tag, to the stream.
    123 inline Status WriteSFixed32(int field_number, const DataPiece& data,
    124                             CodedOutputStream* stream) {
    125   StatusOr<int32> i32 = data.ToInt32();
    126   if (i32.ok()) {
    127     WireFormatLite::WriteSFixed32(field_number, i32.ValueOrDie(), stream);
    128   }
    129   return i32.status();
    130 }
    131 
    132 // Writes an SINT32 field, including tag, to the stream.
    133 inline Status WriteSInt32(int field_number, const DataPiece& data,
    134                           CodedOutputStream* stream) {
    135   StatusOr<int32> i32 = data.ToInt32();
    136   if (i32.ok()) {
    137     WireFormatLite::WriteSInt32(field_number, i32.ValueOrDie(), stream);
    138   }
    139   return i32.status();
    140 }
    141 
    142 // Writes a FIXED32 field, including tag, to the stream.
    143 inline Status WriteFixed32(int field_number, const DataPiece& data,
    144                            CodedOutputStream* stream) {
    145   StatusOr<uint32> u32 = data.ToUint32();
    146   if (u32.ok()) {
    147     WireFormatLite::WriteFixed32(field_number, u32.ValueOrDie(), stream);
    148   }
    149   return u32.status();
    150 }
    151 
    152 // Writes a UINT32 field, including tag, to the stream.
    153 inline Status WriteUInt32(int field_number, const DataPiece& data,
    154                           CodedOutputStream* stream) {
    155   StatusOr<uint32> u32 = data.ToUint32();
    156   if (u32.ok()) {
    157     WireFormatLite::WriteUInt32(field_number, u32.ValueOrDie(), stream);
    158   }
    159   return u32.status();
    160 }
    161 
    162 // Writes an INT64 field, including tag, to the stream.
    163 inline Status WriteInt64(int field_number, const DataPiece& data,
    164                          CodedOutputStream* stream) {
    165   StatusOr<int64> i64 = data.ToInt64();
    166   if (i64.ok()) {
    167     WireFormatLite::WriteInt64(field_number, i64.ValueOrDie(), stream);
    168   }
    169   return i64.status();
    170 }
    171 
    172 // Writes an SFIXED64 field, including tag, to the stream.
    173 inline Status WriteSFixed64(int field_number, const DataPiece& data,
    174                             CodedOutputStream* stream) {
    175   StatusOr<int64> i64 = data.ToInt64();
    176   if (i64.ok()) {
    177     WireFormatLite::WriteSFixed64(field_number, i64.ValueOrDie(), stream);
    178   }
    179   return i64.status();
    180 }
    181 
    182 // Writes an SINT64 field, including tag, to the stream.
    183 inline Status WriteSInt64(int field_number, const DataPiece& data,
    184                           CodedOutputStream* stream) {
    185   StatusOr<int64> i64 = data.ToInt64();
    186   if (i64.ok()) {
    187     WireFormatLite::WriteSInt64(field_number, i64.ValueOrDie(), stream);
    188   }
    189   return i64.status();
    190 }
    191 
    192 // Writes a FIXED64 field, including tag, to the stream.
    193 inline Status WriteFixed64(int field_number, const DataPiece& data,
    194                            CodedOutputStream* stream) {
    195   StatusOr<uint64> u64 = data.ToUint64();
    196   if (u64.ok()) {
    197     WireFormatLite::WriteFixed64(field_number, u64.ValueOrDie(), stream);
    198   }
    199   return u64.status();
    200 }
    201 
    202 // Writes a UINT64 field, including tag, to the stream.
    203 inline Status WriteUInt64(int field_number, const DataPiece& data,
    204                           CodedOutputStream* stream) {
    205   StatusOr<uint64> u64 = data.ToUint64();
    206   if (u64.ok()) {
    207     WireFormatLite::WriteUInt64(field_number, u64.ValueOrDie(), stream);
    208   }
    209   return u64.status();
    210 }
    211 
    212 // Writes a DOUBLE field, including tag, to the stream.
    213 inline Status WriteDouble(int field_number, const DataPiece& data,
    214                           CodedOutputStream* stream) {
    215   StatusOr<double> d = data.ToDouble();
    216   if (d.ok()) {
    217     WireFormatLite::WriteDouble(field_number, d.ValueOrDie(), stream);
    218   }
    219   return d.status();
    220 }
    221 
    222 // Writes a FLOAT field, including tag, to the stream.
    223 inline Status WriteFloat(int field_number, const DataPiece& data,
    224                          CodedOutputStream* stream) {
    225   StatusOr<float> f = data.ToFloat();
    226   if (f.ok()) {
    227     WireFormatLite::WriteFloat(field_number, f.ValueOrDie(), stream);
    228   }
    229   return f.status();
    230 }
    231 
    232 // Writes a BOOL field, including tag, to the stream.
    233 inline Status WriteBool(int field_number, const DataPiece& data,
    234                         CodedOutputStream* stream) {
    235   StatusOr<bool> b = data.ToBool();
    236   if (b.ok()) {
    237     WireFormatLite::WriteBool(field_number, b.ValueOrDie(), stream);
    238   }
    239   return b.status();
    240 }
    241 
    242 // Writes a BYTES field, including tag, to the stream.
    243 inline Status WriteBytes(int field_number, const DataPiece& data,
    244                          CodedOutputStream* stream) {
    245   StatusOr<string> c = data.ToBytes();
    246   if (c.ok()) {
    247     WireFormatLite::WriteBytes(field_number, c.ValueOrDie(), stream);
    248   }
    249   return c.status();
    250 }
    251 
    252 // Writes a STRING field, including tag, to the stream.
    253 inline Status WriteString(int field_number, const DataPiece& data,
    254                           CodedOutputStream* stream) {
    255   StatusOr<string> s = data.ToString();
    256   if (s.ok()) {
    257     WireFormatLite::WriteString(field_number, s.ValueOrDie(), stream);
    258   }
    259   return s.status();
    260 }
    261 
    262 // Writes an ENUM field, including tag, to the stream.
    263 inline Status WriteEnum(int field_number, const DataPiece& data,
    264                         const google::protobuf::Enum* enum_type,
    265                         CodedOutputStream* stream) {
    266   StatusOr<int> e = data.ToEnum(enum_type);
    267   if (e.ok()) {
    268     WireFormatLite::WriteEnum(field_number, e.ValueOrDie(), stream);
    269   }
    270   return e.status();
    271 }
    272 
    273 // Given a google::protobuf::Type, returns the set of all required fields.
    274 std::set<const google::protobuf::Field*> GetRequiredFields(
    275     const google::protobuf::Type& type) {
    276   std::set<const google::protobuf::Field*> required;
    277   for (int i = 0; i < type.fields_size(); i++) {
    278     const google::protobuf::Field& field = type.fields(i);
    279     if (field.cardinality() ==
    280         google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) {
    281       required.insert(&field);
    282     }
    283   }
    284   return required;
    285 }
    286 
    287 }  // namespace
    288 
    289 ProtoWriter::ProtoElement::ProtoElement(const TypeInfo* typeinfo,
    290                                         const google::protobuf::Type& type,
    291                                         ProtoWriter* enclosing)
    292     : BaseElement(NULL),
    293       ow_(enclosing),
    294       parent_field_(NULL),
    295       typeinfo_(typeinfo),
    296       type_(type),
    297       required_fields_(GetRequiredFields(type)),
    298       size_index_(-1),
    299       array_index_(-1) {}
    300 
    301 ProtoWriter::ProtoElement::ProtoElement(ProtoWriter::ProtoElement* parent,
    302                                         const google::protobuf::Field* field,
    303                                         const google::protobuf::Type& type,
    304                                         bool is_list)
    305     : BaseElement(parent),
    306       ow_(this->parent()->ow_),
    307       parent_field_(field),
    308       typeinfo_(this->parent()->typeinfo_),
    309       type_(type),
    310       size_index_(
    311           !is_list && field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE
    312               ? ow_->size_insert_.size()
    313               : -1),
    314       array_index_(is_list ? 0 : -1) {
    315   if (!is_list) {
    316     if (ow_->IsRepeated(*field)) {
    317       // Update array_index_ if it is an explicit list.
    318       if (this->parent()->array_index_ >= 0) this->parent()->array_index_++;
    319     } else {
    320       this->parent()->RegisterField(field);
    321     }
    322 
    323     if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
    324       required_fields_ = GetRequiredFields(type_);
    325       int start_pos = ow_->stream_->ByteCount();
    326       // length of serialized message is the final buffer position minus
    327       // starting buffer position, plus length adjustments for size fields
    328       // of any nested messages. We start with -start_pos here, so we only
    329       // need to add the final buffer position to it at the end.
    330       SizeInfo info = {start_pos, -start_pos};
    331       ow_->size_insert_.push_back(info);
    332     }
    333   }
    334 }
    335 
    336 ProtoWriter::ProtoElement* ProtoWriter::ProtoElement::pop() {
    337   // Calls the registered error listener for any required field(s) not yet
    338   // seen.
    339   for (set<const google::protobuf::Field*>::iterator it =
    340            required_fields_.begin();
    341        it != required_fields_.end(); ++it) {
    342     ow_->MissingField((*it)->name());
    343   }
    344   // Computes the total number of proto bytes used by a message, also adjusts
    345   // the size of all parent messages by the length of this size field.
    346   // If size_index_ < 0, this is not a message, so no size field is added.
    347   if (size_index_ >= 0) {
    348     // Add the final buffer position to compute the total length of this
    349     // serialized message. The stored value (before this addition) already
    350     // contains the total length of the size fields of all nested messages
    351     // minus the initial buffer position.
    352     ow_->size_insert_[size_index_].size += ow_->stream_->ByteCount();
    353     // Calculate the length required to serialize the size field of the
    354     // message, and propagate this additional size information upward to
    355     // all enclosing messages.
    356     int size = ow_->size_insert_[size_index_].size;
    357     int length = CodedOutputStream::VarintSize32(size);
    358     for (ProtoElement* e = parent(); e != NULL; e = e->parent()) {
    359       // Only nested messages have size field, lists do not have size field.
    360       if (e->size_index_ >= 0) {
    361         ow_->size_insert_[e->size_index_].size += length;
    362       }
    363     }
    364   }
    365   return BaseElement::pop<ProtoElement>();
    366 }
    367 
    368 void ProtoWriter::ProtoElement::RegisterField(
    369     const google::protobuf::Field* field) {
    370   if (!required_fields_.empty() &&
    371       field->cardinality() ==
    372           google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) {
    373     required_fields_.erase(field);
    374   }
    375 }
    376 
    377 string ProtoWriter::ProtoElement::ToString() const {
    378   if (parent() == NULL) return "";
    379   string loc = parent()->ToString();
    380   if (!ow_->IsRepeated(*parent_field_) ||
    381       parent()->parent_field_ != parent_field_) {
    382     string name = parent_field_->name();
    383     int i = 0;
    384     while (i < name.size() && (ascii_isalnum(name[i]) || name[i] == '_')) ++i;
    385     if (i > 0 && i == name.size()) {  // safe field name
    386       if (loc.empty()) {
    387         loc = name;
    388       } else {
    389         StrAppend(&loc, ".", name);
    390       }
    391     } else {
    392       StrAppend(&loc, "[\"", CEscape(name), "\"]");
    393     }
    394   }
    395   if (ow_->IsRepeated(*parent_field_) && array_index_ > 0) {
    396     StrAppend(&loc, "[", array_index_ - 1, "]");
    397   }
    398   return loc.empty() ? "." : loc;
    399 }
    400 
    401 bool ProtoWriter::ProtoElement::IsOneofIndexTaken(int32 index) {
    402   return ContainsKey(oneof_indices_, index);
    403 }
    404 
    405 void ProtoWriter::ProtoElement::TakeOneofIndex(int32 index) {
    406   InsertIfNotPresent(&oneof_indices_, index);
    407 }
    408 
    409 void ProtoWriter::InvalidName(StringPiece unknown_name, StringPiece message) {
    410   listener_->InvalidName(location(), ToSnakeCase(unknown_name), message);
    411 }
    412 
    413 void ProtoWriter::InvalidValue(StringPiece type_name, StringPiece value) {
    414   listener_->InvalidValue(location(), type_name, value);
    415 }
    416 
    417 void ProtoWriter::MissingField(StringPiece missing_name) {
    418   listener_->MissingField(location(), missing_name);
    419 }
    420 
    421 ProtoWriter* ProtoWriter::StartObject(StringPiece name) {
    422   // Starting the root message. Create the root ProtoElement and return.
    423   if (element_ == NULL) {
    424     if (!name.empty()) {
    425       InvalidName(name, "Root element should not be named.");
    426     }
    427     element_.reset(new ProtoElement(typeinfo_, master_type_, this));
    428     return this;
    429   }
    430 
    431   const google::protobuf::Field* field = NULL;
    432   field = BeginNamed(name, false);
    433   if (field == NULL) return this;
    434 
    435   // Check to see if this field is a oneof and that no oneof in that group has
    436   // already been set.
    437   if (!ValidOneof(*field, name)) {
    438     ++invalid_depth_;
    439     return this;
    440   }
    441 
    442   const google::protobuf::Type* type = LookupType(field);
    443   if (type == NULL) {
    444     ++invalid_depth_;
    445     InvalidName(name,
    446                 StrCat("Missing descriptor for field: ", field->type_url()));
    447     return this;
    448   }
    449 
    450   return StartObjectField(*field, *type);
    451 }
    452 
    453 ProtoWriter* ProtoWriter::EndObject() {
    454   if (invalid_depth_ > 0) {
    455     --invalid_depth_;
    456     return this;
    457   }
    458 
    459   if (element_ != NULL) {
    460     element_.reset(element_->pop());
    461   }
    462 
    463 
    464   // If ending the root element,
    465   // then serialize the full message with calculated sizes.
    466   if (element_ == NULL) {
    467     WriteRootMessage();
    468   }
    469   return this;
    470 }
    471 
    472 ProtoWriter* ProtoWriter::StartList(StringPiece name) {
    473   const google::protobuf::Field* field = BeginNamed(name, true);
    474   if (field == NULL) return this;
    475 
    476   if (!ValidOneof(*field, name)) {
    477     ++invalid_depth_;
    478     return this;
    479   }
    480 
    481   const google::protobuf::Type* type = LookupType(field);
    482   if (type == NULL) {
    483     ++invalid_depth_;
    484     InvalidName(name,
    485                 StrCat("Missing descriptor for field: ", field->type_url()));
    486     return this;
    487   }
    488 
    489   return StartListField(*field, *type);
    490 }
    491 
    492 ProtoWriter* ProtoWriter::EndList() {
    493   if (invalid_depth_ > 0) {
    494     --invalid_depth_;
    495   } else if (element_ != NULL) {
    496     element_.reset(element_->pop());
    497   }
    498   return this;
    499 }
    500 
    501 ProtoWriter* ProtoWriter::RenderDataPiece(StringPiece name,
    502                                           const DataPiece& data) {
    503   Status status;
    504   if (invalid_depth_ > 0) return this;
    505 
    506   const google::protobuf::Field* field = Lookup(name);
    507   if (field == NULL) return this;
    508 
    509   if (!ValidOneof(*field, name)) return this;
    510 
    511   const google::protobuf::Type* type = LookupType(field);
    512   if (type == NULL) {
    513     InvalidName(name,
    514                 StrCat("Missing descriptor for field: ", field->type_url()));
    515     return this;
    516   }
    517 
    518   return RenderPrimitiveField(*field, *type, data);
    519 }
    520 
    521 bool ProtoWriter::ValidOneof(const google::protobuf::Field& field,
    522                              StringPiece unnormalized_name) {
    523   if (element_ == NULL) return true;
    524 
    525   if (field.oneof_index() > 0) {
    526     if (element_->IsOneofIndexTaken(field.oneof_index())) {
    527       InvalidValue(
    528           "oneof",
    529           StrCat("oneof field '",
    530                  element_->type().oneofs(field.oneof_index() - 1),
    531                  "' is already set. Cannot set '", unnormalized_name, "'"));
    532       return false;
    533     }
    534     element_->TakeOneofIndex(field.oneof_index());
    535   }
    536   return true;
    537 }
    538 
    539 bool ProtoWriter::IsRepeated(const google::protobuf::Field& field) {
    540   return field.cardinality() ==
    541          google::protobuf::Field_Cardinality_CARDINALITY_REPEATED;
    542 }
    543 
    544 ProtoWriter* ProtoWriter::StartObjectField(const google::protobuf::Field& field,
    545                                            const google::protobuf::Type& type) {
    546     WriteTag(field);
    547   element_.reset(new ProtoElement(element_.release(), &field, type, false));
    548   return this;
    549 }
    550 
    551 ProtoWriter* ProtoWriter::StartListField(const google::protobuf::Field& field,
    552                                          const google::protobuf::Type& type) {
    553   element_.reset(new ProtoElement(element_.release(), &field, type, true));
    554   return this;
    555 }
    556 
    557 ProtoWriter* ProtoWriter::RenderPrimitiveField(
    558     const google::protobuf::Field& field, const google::protobuf::Type& type,
    559     const DataPiece& data) {
    560   Status status;
    561 
    562   // Pushing a ProtoElement and then pop it off at the end for 2 purposes:
    563   // error location reporting and required field accounting.
    564   element_.reset(new ProtoElement(element_.release(), &field, type, false));
    565 
    566   if (field.kind() == google::protobuf::Field_Kind_TYPE_UNKNOWN ||
    567       field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
    568     InvalidValue(field.type_url().empty()
    569                      ? google::protobuf::Field_Kind_Name(field.kind())
    570                      : field.type_url(),
    571                  data.ValueAsStringOrDefault(""));
    572     element_.reset(element()->pop());
    573     return this;
    574   }
    575 
    576   switch (field.kind()) {
    577     case google::protobuf::Field_Kind_TYPE_INT32: {
    578       status = WriteInt32(field.number(), data, stream_.get());
    579       break;
    580     }
    581     case google::protobuf::Field_Kind_TYPE_SFIXED32: {
    582       status = WriteSFixed32(field.number(), data, stream_.get());
    583       break;
    584     }
    585     case google::protobuf::Field_Kind_TYPE_SINT32: {
    586       status = WriteSInt32(field.number(), data, stream_.get());
    587       break;
    588     }
    589     case google::protobuf::Field_Kind_TYPE_FIXED32: {
    590       status = WriteFixed32(field.number(), data, stream_.get());
    591       break;
    592     }
    593     case google::protobuf::Field_Kind_TYPE_UINT32: {
    594       status = WriteUInt32(field.number(), data, stream_.get());
    595       break;
    596     }
    597     case google::protobuf::Field_Kind_TYPE_INT64: {
    598       status = WriteInt64(field.number(), data, stream_.get());
    599       break;
    600     }
    601     case google::protobuf::Field_Kind_TYPE_SFIXED64: {
    602       status = WriteSFixed64(field.number(), data, stream_.get());
    603       break;
    604     }
    605     case google::protobuf::Field_Kind_TYPE_SINT64: {
    606       status = WriteSInt64(field.number(), data, stream_.get());
    607       break;
    608     }
    609     case google::protobuf::Field_Kind_TYPE_FIXED64: {
    610       status = WriteFixed64(field.number(), data, stream_.get());
    611       break;
    612     }
    613     case google::protobuf::Field_Kind_TYPE_UINT64: {
    614       status = WriteUInt64(field.number(), data, stream_.get());
    615       break;
    616     }
    617     case google::protobuf::Field_Kind_TYPE_DOUBLE: {
    618       status = WriteDouble(field.number(), data, stream_.get());
    619       break;
    620     }
    621     case google::protobuf::Field_Kind_TYPE_FLOAT: {
    622       status = WriteFloat(field.number(), data, stream_.get());
    623       break;
    624     }
    625     case google::protobuf::Field_Kind_TYPE_BOOL: {
    626       status = WriteBool(field.number(), data, stream_.get());
    627       break;
    628     }
    629     case google::protobuf::Field_Kind_TYPE_BYTES: {
    630       status = WriteBytes(field.number(), data, stream_.get());
    631       break;
    632     }
    633     case google::protobuf::Field_Kind_TYPE_STRING: {
    634       status = WriteString(field.number(), data, stream_.get());
    635       break;
    636     }
    637     case google::protobuf::Field_Kind_TYPE_ENUM: {
    638       status = WriteEnum(field.number(), data,
    639                          typeinfo_->GetEnumByTypeUrl(field.type_url()),
    640                          stream_.get());
    641       break;
    642     }
    643     default:  // TYPE_GROUP or TYPE_MESSAGE
    644       status = Status(INVALID_ARGUMENT, data.ToString().ValueOrDie());
    645   }
    646 
    647   if (!status.ok()) {
    648     InvalidValue(google::protobuf::Field_Kind_Name(field.kind()),
    649                  status.error_message());
    650   }
    651 
    652   element_.reset(element()->pop());
    653   return this;
    654 }
    655 
    656 const google::protobuf::Field* ProtoWriter::BeginNamed(StringPiece name,
    657                                                        bool is_list) {
    658   if (invalid_depth_ > 0) {
    659     ++invalid_depth_;
    660     return NULL;
    661   }
    662   const google::protobuf::Field* field = Lookup(name);
    663   if (field == NULL) {
    664     ++invalid_depth_;
    665     // InvalidName() already called in Lookup().
    666     return NULL;
    667   }
    668   if (is_list && !IsRepeated(*field)) {
    669     ++invalid_depth_;
    670     InvalidName(name, "Proto field is not repeating, cannot start list.");
    671     return NULL;
    672   }
    673   return field;
    674 }
    675 
    676 const google::protobuf::Field* ProtoWriter::Lookup(
    677     StringPiece unnormalized_name) {
    678   ProtoElement* e = element();
    679   if (e == NULL) {
    680     InvalidName(unnormalized_name, "Root element must be a message.");
    681     return NULL;
    682   }
    683   if (unnormalized_name.empty()) {
    684     // Objects in repeated field inherit the same field descriptor.
    685     if (e->parent_field() == NULL) {
    686       InvalidName(unnormalized_name, "Proto fields must have a name.");
    687     } else if (!IsRepeated(*e->parent_field())) {
    688       InvalidName(unnormalized_name, "Proto fields must have a name.");
    689       return NULL;
    690     }
    691     return e->parent_field();
    692   }
    693   const google::protobuf::Field* field =
    694       typeinfo_->FindField(&e->type(), unnormalized_name);
    695   if (field == NULL) InvalidName(unnormalized_name, "Cannot find field.");
    696   return field;
    697 }
    698 
    699 const google::protobuf::Type* ProtoWriter::LookupType(
    700     const google::protobuf::Field* field) {
    701   return ((field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE ||
    702            field->kind() == google::protobuf::Field_Kind_TYPE_GROUP)
    703               ? typeinfo_->GetTypeByTypeUrl(field->type_url())
    704               : &element_->type());
    705 }
    706 
    707 void ProtoWriter::WriteRootMessage() {
    708   GOOGLE_DCHECK(!done_);
    709   int curr_pos = 0;
    710   // Calls the destructor of CodedOutputStream to remove any uninitialized
    711   // memory from the Cord before we read it.
    712   stream_.reset(NULL);
    713   const void* data;
    714   int length;
    715   google::protobuf::io::ArrayInputStream input_stream(buffer_.data(), buffer_.size());
    716   while (input_stream.Next(&data, &length)) {
    717     if (length == 0) continue;
    718     int num_bytes = length;
    719     // Write up to where we need to insert the size field.
    720     // The number of bytes we may write is the smaller of:
    721     //   - the current fragment size
    722     //   - the distance to the next position where a size field needs to be
    723     //     inserted.
    724     if (!size_insert_.empty() &&
    725         size_insert_.front().pos - curr_pos < num_bytes) {
    726       num_bytes = size_insert_.front().pos - curr_pos;
    727     }
    728     output_->Append(static_cast<const char*>(data), num_bytes);
    729     if (num_bytes < length) {
    730       input_stream.BackUp(length - num_bytes);
    731     }
    732     curr_pos += num_bytes;
    733     // Insert the size field.
    734     //   size_insert_.front():      the next <index, size> pair to be written.
    735     //   size_insert_.front().pos:  position of the size field.
    736     //   size_insert_.front().size: the size (integer) to be inserted.
    737     if (!size_insert_.empty() && curr_pos == size_insert_.front().pos) {
    738       // Varint32 occupies at most 10 bytes.
    739       uint8 insert_buffer[10];
    740       uint8* insert_buffer_pos = CodedOutputStream::WriteVarint32ToArray(
    741           size_insert_.front().size, insert_buffer);
    742       output_->Append(reinterpret_cast<const char*>(insert_buffer),
    743                       insert_buffer_pos - insert_buffer);
    744       size_insert_.pop_front();
    745     }
    746   }
    747   output_->Flush();
    748   stream_.reset(new CodedOutputStream(&adapter_));
    749   done_ = true;
    750 }
    751 
    752 void ProtoWriter::WriteTag(const google::protobuf::Field& field) {
    753   WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType(
    754       static_cast<WireFormatLite::FieldType>(field.kind()));
    755   stream_->WriteTag(WireFormatLite::MakeTag(field.number(), wire_type));
    756 }
    757 
    758 
    759 }  // namespace converter
    760 }  // namespace util
    761 }  // namespace protobuf
    762 }  // namespace google
    763