OLD | NEW |
1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
4 // | 4 // |
5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
7 // met: | 7 // met: |
8 // | 8 // |
9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 const google::protobuf::Type& type, int number); | 78 const google::protobuf::Type& type, int number); |
79 | 79 |
80 // Returns true if the field is packable. | 80 // Returns true if the field is packable. |
81 bool IsPackable(const google::protobuf::Field& field); | 81 bool IsPackable(const google::protobuf::Field& field); |
82 | 82 |
83 // Finds an enum value with the given number. NULL if none found. | 83 // Finds an enum value with the given number. NULL if none found. |
84 const google::protobuf::EnumValue* FindEnumValueByNumber( | 84 const google::protobuf::EnumValue* FindEnumValueByNumber( |
85 const google::protobuf::Enum& tech_enum, int number); | 85 const google::protobuf::Enum& tech_enum, int number); |
86 | 86 |
87 // Utility function to format nanos. | 87 // Utility function to format nanos. |
88 const string FormatNanos(uint32 nanos); | 88 const string FormatNanos(uint32 nanos, bool with_trailing_zeros); |
89 | 89 |
90 StatusOr<string> MapKeyDefaultValueAsString( | 90 StatusOr<string> MapKeyDefaultValueAsString( |
91 const google::protobuf::Field& field) { | 91 const google::protobuf::Field& field) { |
92 switch (field.kind()) { | 92 switch (field.kind()) { |
93 case google::protobuf::Field_Kind_TYPE_BOOL: | 93 case google::protobuf::Field_Kind_TYPE_BOOL: |
94 return string("false"); | 94 return string("false"); |
95 case google::protobuf::Field_Kind_TYPE_INT32: | 95 case google::protobuf::Field_Kind_TYPE_INT32: |
96 case google::protobuf::Field_Kind_TYPE_INT64: | 96 case google::protobuf::Field_Kind_TYPE_INT64: |
97 case google::protobuf::Field_Kind_TYPE_UINT32: | 97 case google::protobuf::Field_Kind_TYPE_UINT32: |
98 case google::protobuf::Field_Kind_TYPE_UINT64: | 98 case google::protobuf::Field_Kind_TYPE_UINT64: |
(...skipping 15 matching lines...) Expand all Loading... |
114 | 114 |
115 ProtoStreamObjectSource::ProtoStreamObjectSource( | 115 ProtoStreamObjectSource::ProtoStreamObjectSource( |
116 google::protobuf::io::CodedInputStream* stream, TypeResolver* type_resolver, | 116 google::protobuf::io::CodedInputStream* stream, TypeResolver* type_resolver, |
117 const google::protobuf::Type& type) | 117 const google::protobuf::Type& type) |
118 : stream_(stream), | 118 : stream_(stream), |
119 typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), | 119 typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), |
120 own_typeinfo_(true), | 120 own_typeinfo_(true), |
121 type_(type), | 121 type_(type), |
122 use_lower_camel_for_enums_(false), | 122 use_lower_camel_for_enums_(false), |
123 recursion_depth_(0), | 123 recursion_depth_(0), |
124 max_recursion_depth_(kDefaultMaxRecursionDepth) { | 124 max_recursion_depth_(kDefaultMaxRecursionDepth), |
| 125 render_unknown_fields_(false), |
| 126 add_trailing_zeros_for_timestamp_and_duration_(false) { |
125 GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL."; | 127 GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL."; |
126 } | 128 } |
127 | 129 |
128 ProtoStreamObjectSource::ProtoStreamObjectSource( | 130 ProtoStreamObjectSource::ProtoStreamObjectSource( |
129 google::protobuf::io::CodedInputStream* stream, const TypeInfo* typeinfo, | 131 google::protobuf::io::CodedInputStream* stream, const TypeInfo* typeinfo, |
130 const google::protobuf::Type& type) | 132 const google::protobuf::Type& type) |
131 : stream_(stream), | 133 : stream_(stream), |
132 typeinfo_(typeinfo), | 134 typeinfo_(typeinfo), |
133 own_typeinfo_(false), | 135 own_typeinfo_(false), |
134 type_(type), | 136 type_(type), |
135 use_lower_camel_for_enums_(false), | 137 use_lower_camel_for_enums_(false), |
136 recursion_depth_(0), | 138 recursion_depth_(0), |
137 max_recursion_depth_(kDefaultMaxRecursionDepth) { | 139 max_recursion_depth_(kDefaultMaxRecursionDepth), |
| 140 render_unknown_fields_(false), |
| 141 add_trailing_zeros_for_timestamp_and_duration_(false) { |
138 GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL."; | 142 GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL."; |
139 } | 143 } |
140 | 144 |
141 ProtoStreamObjectSource::~ProtoStreamObjectSource() { | 145 ProtoStreamObjectSource::~ProtoStreamObjectSource() { |
142 if (own_typeinfo_) { | 146 if (own_typeinfo_) { |
143 delete typeinfo_; | 147 delete typeinfo_; |
144 } | 148 } |
145 } | 149 } |
146 | 150 |
147 Status ProtoStreamObjectSource::NamedWriteTo(StringPiece name, | 151 Status ProtoStreamObjectSource::NamedWriteTo(StringPiece name, |
(...skipping 29 matching lines...) Expand all Loading... |
177 | 181 |
178 const TypeRenderer* type_renderer = FindTypeRenderer(type.name()); | 182 const TypeRenderer* type_renderer = FindTypeRenderer(type.name()); |
179 if (type_renderer != NULL) { | 183 if (type_renderer != NULL) { |
180 return (*type_renderer)(this, type, name, ow); | 184 return (*type_renderer)(this, type, name, ow); |
181 } | 185 } |
182 | 186 |
183 const google::protobuf::Field* field = NULL; | 187 const google::protobuf::Field* field = NULL; |
184 string field_name; | 188 string field_name; |
185 // last_tag set to dummy value that is different from tag. | 189 // last_tag set to dummy value that is different from tag. |
186 uint32 tag = stream_->ReadTag(), last_tag = tag + 1; | 190 uint32 tag = stream_->ReadTag(), last_tag = tag + 1; |
| 191 google::protobuf::UnknownFieldSet unknown_fields; |
187 | 192 |
188 if (include_start_and_end) { | 193 if (include_start_and_end) { |
189 ow->StartObject(name); | 194 ow->StartObject(name); |
190 } | 195 } |
191 while (tag != end_tag) { | 196 while (tag != end_tag) { |
192 if (tag != last_tag) { // Update field only if tag is changed. | 197 if (tag != last_tag) { // Update field only if tag is changed. |
193 last_tag = tag; | 198 last_tag = tag; |
194 field = FindAndVerifyField(type, tag); | 199 field = FindAndVerifyField(type, tag); |
195 if (field != NULL) { | 200 if (field != NULL) { |
196 field_name = field->json_name(); | 201 field_name = field->json_name(); |
197 } | 202 } |
198 } | 203 } |
199 if (field == NULL) { | 204 if (field == NULL) { |
200 // If we didn't find a field, skip this unknown tag. | 205 // If we didn't find a field, skip this unknown tag. |
201 // TODO(wpoon): Check return boolean value. | 206 // TODO(wpoon): Check return boolean value. |
202 WireFormat::SkipField(stream_, tag, NULL); | 207 WireFormat::SkipField(stream_, tag, |
| 208 render_unknown_fields_ ? &unknown_fields : NULL); |
203 tag = stream_->ReadTag(); | 209 tag = stream_->ReadTag(); |
204 continue; | 210 continue; |
205 } | 211 } |
206 | 212 |
207 if (field->cardinality() == | 213 if (field->cardinality() == |
208 google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) { | 214 google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) { |
209 bool check_maps = true; | 215 bool check_maps = true; |
210 | 216 |
211 if (check_maps && IsMap(*field)) { | 217 if (check_maps && IsMap(*field)) { |
212 ow->StartObject(field_name); | 218 ow->StartObject(field_name); |
213 ASSIGN_OR_RETURN(tag, RenderMap(field, field_name, tag, ow)); | 219 ASSIGN_OR_RETURN(tag, RenderMap(field, field_name, tag, ow)); |
214 ow->EndObject(); | 220 ow->EndObject(); |
215 } else { | 221 } else { |
216 ASSIGN_OR_RETURN(tag, RenderList(field, field_name, tag, ow)); | 222 ASSIGN_OR_RETURN(tag, RenderList(field, field_name, tag, ow)); |
217 } | 223 } |
218 } else { | 224 } else { |
219 // Render the field. | 225 // Render the field. |
220 RETURN_IF_ERROR(RenderField(field, field_name, ow)); | 226 RETURN_IF_ERROR(RenderField(field, field_name, ow)); |
221 tag = stream_->ReadTag(); | 227 tag = stream_->ReadTag(); |
222 } | 228 } |
223 } | 229 } |
| 230 |
| 231 |
224 if (include_start_and_end) { | 232 if (include_start_and_end) { |
225 ow->EndObject(); | 233 ow->EndObject(); |
226 } | 234 } |
227 return Status::OK; | 235 return Status::OK; |
228 } | 236 } |
229 | 237 |
230 StatusOr<uint32> ProtoStreamObjectSource::RenderList( | 238 StatusOr<uint32> ProtoStreamObjectSource::RenderList( |
231 const google::protobuf::Field* field, StringPiece name, uint32 list_tag, | 239 const google::protobuf::Field* field, StringPiece name, uint32 list_tag, |
232 ObjectWriter* ow) const { | 240 ObjectWriter* ow) const { |
233 uint32 tag_to_return = 0; | 241 uint32 tag_to_return = 0; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 if (map_key.empty()) { | 283 if (map_key.empty()) { |
276 // An absent map key is treated as the default. | 284 // An absent map key is treated as the default. |
277 const google::protobuf::Field* key_field = | 285 const google::protobuf::Field* key_field = |
278 FindFieldByNumber(*field_type, 1); | 286 FindFieldByNumber(*field_type, 1); |
279 if (key_field == NULL) { | 287 if (key_field == NULL) { |
280 // The Type info for this map entry is incorrect. It should always | 288 // The Type info for this map entry is incorrect. It should always |
281 // have a field named "key" and with field number 1. | 289 // have a field named "key" and with field number 1. |
282 return Status(util::error::INTERNAL, "Invalid map entry."); | 290 return Status(util::error::INTERNAL, "Invalid map entry."); |
283 } | 291 } |
284 ASSIGN_OR_RETURN(map_key, MapKeyDefaultValueAsString(*key_field)); | 292 ASSIGN_OR_RETURN(map_key, MapKeyDefaultValueAsString(*key_field)); |
| 293 // Key is empty, force it to render as empty (for string values). |
| 294 ow->empty_name_ok_for_next_key(); |
285 } | 295 } |
286 RETURN_IF_ERROR(RenderField(field, map_key, ow)); | 296 RETURN_IF_ERROR(RenderField(field, map_key, ow)); |
287 } else { | 297 } else { |
288 // The Type info for this map entry is incorrect. It should contain | 298 // The Type info for this map entry is incorrect. It should contain |
289 // exactly two fields with field number 1 and 2. | 299 // exactly two fields with field number 1 and 2. |
290 return Status(util::error::INTERNAL, "Invalid map entry."); | 300 return Status(util::error::INTERNAL, "Invalid map entry."); |
291 } | 301 } |
292 } | 302 } |
293 stream_->PopLimit(old_limit); | 303 stream_->PopLimit(old_limit); |
294 } while ((tag_to_return = stream_->ReadTag()) == list_tag); | 304 } while ((tag_to_return = stream_->ReadTag()) == list_tag); |
295 return tag_to_return; | 305 return tag_to_return; |
296 } | 306 } |
297 | 307 |
298 Status ProtoStreamObjectSource::RenderPacked( | 308 Status ProtoStreamObjectSource::RenderPacked( |
299 const google::protobuf::Field* field, ObjectWriter* ow) const { | 309 const google::protobuf::Field* field, ObjectWriter* ow) const { |
300 uint32 length; | 310 uint32 length; |
301 stream_->ReadVarint32(&length); | 311 stream_->ReadVarint32(&length); |
302 int old_limit = stream_->PushLimit(length); | 312 int old_limit = stream_->PushLimit(length); |
303 while (stream_->BytesUntilLimit() > 0) { | 313 while (stream_->BytesUntilLimit() > 0) { |
304 RETURN_IF_ERROR(RenderField(field, StringPiece(), ow)); | 314 RETURN_IF_ERROR(RenderField(field, StringPiece(), ow)); |
305 } | 315 } |
306 stream_->PopLimit(old_limit); | 316 stream_->PopLimit(old_limit); |
307 return Status::OK; | 317 return Status::OK; |
308 } | 318 } |
309 | 319 |
310 Status ProtoStreamObjectSource::RenderTimestamp( | 320 Status ProtoStreamObjectSource::RenderTimestamp( |
311 const ProtoStreamObjectSource* os, const google::protobuf::Type& type, | 321 const ProtoStreamObjectSource* os, const google::protobuf::Type& type, |
312 StringPiece field_name, ObjectWriter* ow) { | 322 StringPiece field_name, ObjectWriter* ow) { |
313 pair<int64, int32> p = os->ReadSecondsAndNanos(type); | 323 std::pair<int64, int32> p = os->ReadSecondsAndNanos(type); |
314 int64 seconds = p.first; | 324 int64 seconds = p.first; |
315 int32 nanos = p.second; | 325 int32 nanos = p.second; |
316 if (seconds > kTimestampMaxSeconds || seconds < kTimestampMinSeconds) { | 326 if (seconds > kTimestampMaxSeconds || seconds < kTimestampMinSeconds) { |
317 return Status( | 327 return Status( |
318 util::error::INTERNAL, | 328 util::error::INTERNAL, |
319 StrCat("Timestamp seconds exceeds limit for field: ", field_name)); | 329 StrCat("Timestamp seconds exceeds limit for field: ", field_name)); |
320 } | 330 } |
321 | 331 |
322 if (nanos < 0 || nanos >= kNanosPerSecond) { | 332 if (nanos < 0 || nanos >= kNanosPerSecond) { |
323 return Status( | 333 return Status( |
324 util::error::INTERNAL, | 334 util::error::INTERNAL, |
325 StrCat("Timestamp nanos exceeds limit for field: ", field_name)); | 335 StrCat("Timestamp nanos exceeds limit for field: ", field_name)); |
326 } | 336 } |
327 | 337 |
328 ow->RenderString(field_name, | 338 ow->RenderString(field_name, |
329 ::google::protobuf::internal::FormatTime(seconds, nanos)); | 339 ::google::protobuf::internal::FormatTime(seconds, nanos)); |
330 | 340 |
331 return Status::OK; | 341 return Status::OK; |
332 } | 342 } |
333 | 343 |
334 Status ProtoStreamObjectSource::RenderDuration( | 344 Status ProtoStreamObjectSource::RenderDuration( |
335 const ProtoStreamObjectSource* os, const google::protobuf::Type& type, | 345 const ProtoStreamObjectSource* os, const google::protobuf::Type& type, |
336 StringPiece field_name, ObjectWriter* ow) { | 346 StringPiece field_name, ObjectWriter* ow) { |
337 pair<int64, int32> p = os->ReadSecondsAndNanos(type); | 347 std::pair<int64, int32> p = os->ReadSecondsAndNanos(type); |
338 int64 seconds = p.first; | 348 int64 seconds = p.first; |
339 int32 nanos = p.second; | 349 int32 nanos = p.second; |
340 if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds) { | 350 if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds) { |
341 return Status( | 351 return Status( |
342 util::error::INTERNAL, | 352 util::error::INTERNAL, |
343 StrCat("Duration seconds exceeds limit for field: ", field_name)); | 353 StrCat("Duration seconds exceeds limit for field: ", field_name)); |
344 } | 354 } |
345 | 355 |
346 if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) { | 356 if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) { |
347 return Status( | 357 return Status( |
348 util::error::INTERNAL, | 358 util::error::INTERNAL, |
349 StrCat("Duration nanos exceeds limit for field: ", field_name)); | 359 StrCat("Duration nanos exceeds limit for field: ", field_name)); |
350 } | 360 } |
351 | 361 |
352 string sign = ""; | 362 string sign = ""; |
353 if (seconds < 0) { | 363 if (seconds < 0) { |
354 if (nanos > 0) { | 364 if (nanos > 0) { |
355 return Status(util::error::INTERNAL, | 365 return Status(util::error::INTERNAL, |
356 StrCat("Duration nanos is non-negative, but seconds is " | 366 StrCat("Duration nanos is non-negative, but seconds is " |
357 "negative for field: ", | 367 "negative for field: ", |
358 field_name)); | 368 field_name)); |
359 } | 369 } |
360 sign = "-"; | 370 sign = "-"; |
361 seconds = -seconds; | 371 seconds = -seconds; |
362 nanos = -nanos; | 372 nanos = -nanos; |
363 } else if (seconds == 0 && nanos < 0) { | 373 } else if (seconds == 0 && nanos < 0) { |
364 sign = "-"; | 374 sign = "-"; |
365 nanos = -nanos; | 375 nanos = -nanos; |
366 } | 376 } |
367 string formatted_duration = StringPrintf("%s%lld%ss", sign.c_str(), seconds, | 377 string formatted_duration = StringPrintf( |
368 FormatNanos(nanos).c_str()); | 378 "%s%lld%ss", sign.c_str(), seconds, |
| 379 FormatNanos(nanos, os->add_trailing_zeros_for_timestamp_and_duration_) |
| 380 .c_str()); |
369 ow->RenderString(field_name, formatted_duration); | 381 ow->RenderString(field_name, formatted_duration); |
370 return Status::OK; | 382 return Status::OK; |
371 } | 383 } |
372 | 384 |
373 Status ProtoStreamObjectSource::RenderDouble(const ProtoStreamObjectSource* os, | 385 Status ProtoStreamObjectSource::RenderDouble(const ProtoStreamObjectSource* os, |
374 const google::protobuf::Type& type, | 386 const google::protobuf::Type& type, |
375 StringPiece field_name, | 387 StringPiece field_name, |
376 ObjectWriter* ow) { | 388 ObjectWriter* ow) { |
377 uint32 tag = os->stream_->ReadTag(); | 389 uint32 tag = os->stream_->ReadTag(); |
378 uint64 buffer64 = 0; // default value of Double wrapper value | 390 uint64 buffer64 = 0; // default value of Double wrapper value |
(...skipping 465 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
844 if (field->type_url() == kStructNullValueTypeUrl) { | 856 if (field->type_url() == kStructNullValueTypeUrl) { |
845 ow->RenderNull(field_name); | 857 ow->RenderNull(field_name); |
846 break; | 858 break; |
847 } | 859 } |
848 | 860 |
849 // Get the nested enum type for this field. | 861 // Get the nested enum type for this field. |
850 // TODO(skarvaje): Avoid string manipulation. Find ways to speed this | 862 // TODO(skarvaje): Avoid string manipulation. Find ways to speed this |
851 // up. | 863 // up. |
852 const google::protobuf::Enum* en = | 864 const google::protobuf::Enum* en = |
853 typeinfo_->GetEnumByTypeUrl(field->type_url()); | 865 typeinfo_->GetEnumByTypeUrl(field->type_url()); |
854 // Lookup the name of the enum, and render that. Skips unknown enums. | 866 // Lookup the name of the enum, and render that. Unknown enum values |
| 867 // are printed as integers. |
855 if (en != NULL) { | 868 if (en != NULL) { |
856 const google::protobuf::EnumValue* enum_value = | 869 const google::protobuf::EnumValue* enum_value = |
857 FindEnumValueByNumber(*en, buffer32); | 870 FindEnumValueByNumber(*en, buffer32); |
858 if (enum_value != NULL) { | 871 if (enum_value != NULL) { |
859 if (use_lower_camel_for_enums_) | 872 if (use_lower_camel_for_enums_) |
860 ow->RenderString(field_name, ToCamelCase(enum_value->name())); | 873 ow->RenderString(field_name, ToCamelCase(enum_value->name())); |
861 else | 874 else |
862 ow->RenderString(field_name, enum_value->name()); | 875 ow->RenderString(field_name, enum_value->name()); |
| 876 } else { |
| 877 ow->RenderInt32(field_name, buffer32); |
863 } | 878 } |
864 } else { | 879 } else { |
865 GOOGLE_LOG(INFO) << "Unknown enum skipped: " << field->type_url(); | 880 ow->RenderInt32(field_name, buffer32); |
866 } | 881 } |
867 break; | 882 break; |
868 } | 883 } |
869 case google::protobuf::Field_Kind_TYPE_STRING: { | 884 case google::protobuf::Field_Kind_TYPE_STRING: { |
870 stream_->ReadVarint32(&buffer32); // string size. | 885 stream_->ReadVarint32(&buffer32); // string size. |
871 stream_->ReadString(&strbuffer, buffer32); | 886 stream_->ReadString(&strbuffer, buffer32); |
872 ow->RenderString(field_name, strbuffer); | 887 ow->RenderString(field_name, strbuffer); |
873 break; | 888 break; |
874 } | 889 } |
875 case google::protobuf::Field_Kind_TYPE_BYTES: { | 890 case google::protobuf::Field_Kind_TYPE_BYTES: { |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1006 // Field is a map if it is a repeated message and it has an option "map_type". | 1021 // 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. | 1022 // TODO(skarvaje): Consider pre-computing the IsMap() into Field directly. |
1008 bool ProtoStreamObjectSource::IsMap( | 1023 bool ProtoStreamObjectSource::IsMap( |
1009 const google::protobuf::Field& field) const { | 1024 const google::protobuf::Field& field) const { |
1010 const google::protobuf::Type* field_type = | 1025 const google::protobuf::Type* field_type = |
1011 typeinfo_->GetTypeByTypeUrl(field.type_url()); | 1026 typeinfo_->GetTypeByTypeUrl(field.type_url()); |
1012 | 1027 |
1013 // TODO(xiaofeng): Unify option names. | 1028 // TODO(xiaofeng): Unify option names. |
1014 return field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE && | 1029 return field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE && |
1015 (GetBoolOptionOrDefault(field_type->options(), | 1030 (GetBoolOptionOrDefault(field_type->options(), |
1016 "google.protobuf.MessageOptions.map_entry", fal
se) || | 1031 "google.protobuf.MessageOptions.map_entry", |
1017 GetBoolOptionOrDefault(field_type->options(), "map_entry", false)); | 1032 false) || |
| 1033 GetBoolOptionOrDefault(field_type->options(), "map_entry", false) || |
| 1034 GetBoolOptionOrDefault(field_type->options(), |
| 1035 "proto2.MessageOptions.map_entry", false)); |
1018 } | 1036 } |
1019 | 1037 |
1020 std::pair<int64, int32> ProtoStreamObjectSource::ReadSecondsAndNanos( | 1038 std::pair<int64, int32> ProtoStreamObjectSource::ReadSecondsAndNanos( |
1021 const google::protobuf::Type& type) const { | 1039 const google::protobuf::Type& type) const { |
1022 uint64 seconds = 0; | 1040 uint64 seconds = 0; |
1023 uint32 nanos = 0; | 1041 uint32 nanos = 0; |
1024 uint32 tag = 0; | 1042 uint32 tag = 0; |
1025 int64 signed_seconds = 0; | 1043 int64 signed_seconds = 0; |
1026 int32 signed_nanos = 0; | 1044 int32 signed_nanos = 0; |
1027 | 1045 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1085 const google::protobuf::EnumValue& ev = tech_enum.enumvalue(i); | 1103 const google::protobuf::EnumValue& ev = tech_enum.enumvalue(i); |
1086 if (ev.number() == number) { | 1104 if (ev.number() == number) { |
1087 return &ev; | 1105 return &ev; |
1088 } | 1106 } |
1089 } | 1107 } |
1090 return NULL; | 1108 return NULL; |
1091 } | 1109 } |
1092 | 1110 |
1093 // TODO(skarvaje): Look into optimizing this by not doing computation on | 1111 // TODO(skarvaje): Look into optimizing this by not doing computation on |
1094 // double. | 1112 // double. |
1095 const string FormatNanos(uint32 nanos) { | 1113 const string FormatNanos(uint32 nanos, bool with_trailing_zeros) { |
| 1114 if (nanos == 0) { |
| 1115 return with_trailing_zeros ? ".000" : ""; |
| 1116 } |
| 1117 |
1096 const char* format = | 1118 const char* format = |
1097 (nanos % 1000 != 0) ? "%.9f" : (nanos % 1000000 != 0) ? "%.6f" : "%.3f"; | 1119 (nanos % 1000 != 0) ? "%.9f" : (nanos % 1000000 != 0) ? "%.6f" : "%.3f"; |
1098 string formatted = | 1120 string formatted = |
1099 StringPrintf(format, static_cast<double>(nanos) / kNanosPerSecond); | 1121 StringPrintf(format, static_cast<double>(nanos) / kNanosPerSecond); |
1100 // remove the leading 0 before decimal. | 1122 // remove the leading 0 before decimal. |
1101 return formatted.substr(1); | 1123 return formatted.substr(1); |
1102 } | 1124 } |
1103 } // namespace | 1125 } // namespace |
1104 | 1126 |
1105 } // namespace converter | 1127 } // namespace converter |
1106 } // namespace util | 1128 } // namespace util |
1107 } // namespace protobuf | 1129 } // namespace protobuf |
1108 } // namespace google | 1130 } // namespace google |
| 1131 |
OLD | NEW |