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