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