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