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