Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: third_party/protobuf/src/google/protobuf/util/internal/protostream_objectsource.cc

Issue 1322483002: Revert https://codereview.chromium.org/1291903002 (protobuf roll). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698