blob: 034d616ff18d4c50c392ed7bcb08d481d4643226 [file] [log] [blame]
Feng Xiaoe96ff302015-06-15 18:21:48 -07001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31#include <google/protobuf/util/internal/protostream_objectsource.h>
32
33#include <utility>
34
35#include <google/protobuf/stubs/casts.h>
Feng Xiaoeee38b02015-08-22 18:25:48 -070036#include <google/protobuf/stubs/logging.h>
Feng Xiaoe96ff302015-06-15 18:21:48 -070037#include <google/protobuf/stubs/common.h>
38#include <google/protobuf/stubs/stringprintf.h>
39#include <google/protobuf/stubs/time.h>
40#include <google/protobuf/io/coded_stream.h>
41#include <google/protobuf/io/zero_copy_stream_impl.h>
42#include <google/protobuf/descriptor.h>
43#include <google/protobuf/wire_format.h>
44#include <google/protobuf/wire_format_lite.h>
45#include <google/protobuf/util/internal/field_mask_utility.h>
46#include <google/protobuf/util/internal/constants.h>
47#include <google/protobuf/util/internal/utility.h>
48#include <google/protobuf/stubs/strutil.h>
49#include <google/protobuf/stubs/map_util.h>
50#include <google/protobuf/stubs/status_macros.h>
51
52
53namespace google {
54namespace protobuf {
55namespace util {
56using util::Status;
57using util::StatusOr;
58namespace error {
59using util::error::Code;
60using util::error::INTERNAL;
61}
62namespace converter {
63
64using google::protobuf::Descriptor;
65using google::protobuf::EnumValueDescriptor;
66using google::protobuf::FieldDescriptor;
67using google::protobuf::internal::WireFormat;
68using google::protobuf::internal::WireFormatLite;
69using util::Status;
70using util::StatusOr;
71
72namespace {
73// Finds a field with the given number. NULL if none found.
74const google::protobuf::Field* FindFieldByNumber(
75 const google::protobuf::Type& type, int number);
76
77// Returns true if the field is packable.
78bool IsPackable(const google::protobuf::Field& field);
79
80// Finds an enum value with the given number. NULL if none found.
81const google::protobuf::EnumValue* FindEnumValueByNumber(
82 const google::protobuf::Enum& tech_enum, int number);
83
84// Utility function to format nanos.
85const string FormatNanos(uint32 nanos);
86} // namespace
87
88
89ProtoStreamObjectSource::ProtoStreamObjectSource(
90 google::protobuf::io::CodedInputStream* stream, TypeResolver* type_resolver,
91 const google::protobuf::Type& type)
92 : stream_(stream),
93 typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
94 own_typeinfo_(true),
95 type_(type) {
96 GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL.";
97}
98
99ProtoStreamObjectSource::ProtoStreamObjectSource(
Feng Xiaoeee38b02015-08-22 18:25:48 -0700100 google::protobuf::io::CodedInputStream* stream, const TypeInfo* typeinfo,
Feng Xiaoe96ff302015-06-15 18:21:48 -0700101 const google::protobuf::Type& type)
102 : stream_(stream), typeinfo_(typeinfo), own_typeinfo_(false), type_(type) {
103 GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL.";
104}
105
106ProtoStreamObjectSource::~ProtoStreamObjectSource() {
107 if (own_typeinfo_) {
108 delete typeinfo_;
109 }
110}
111
112Status ProtoStreamObjectSource::NamedWriteTo(StringPiece name,
113 ObjectWriter* ow) const {
114 return WriteMessage(type_, name, 0, true, ow);
115}
116
117const google::protobuf::Field* ProtoStreamObjectSource::FindAndVerifyField(
118 const google::protobuf::Type& type, uint32 tag) const {
119 // Lookup the new field in the type by tag number.
120 const google::protobuf::Field* field = FindFieldByNumber(type, tag >> 3);
121 // Verify if the field corresponds to the wire type in tag.
122 // If there is any discrepancy, mark the field as not found.
123 if (field != NULL) {
124 WireFormatLite::WireType expected_type =
125 WireFormatLite::WireTypeForFieldType(
126 static_cast<WireFormatLite::FieldType>(field->kind()));
127 WireFormatLite::WireType actual_type = WireFormatLite::GetTagWireType(tag);
128 if (actual_type != expected_type &&
129 (!IsPackable(*field) ||
130 actual_type != WireFormatLite::WIRETYPE_LENGTH_DELIMITED)) {
131 field = NULL;
132 }
133 }
134 return field;
135}
136
137Status ProtoStreamObjectSource::WriteMessage(const google::protobuf::Type& type,
138 StringPiece name,
139 const uint32 end_tag,
140 bool include_start_and_end,
141 ObjectWriter* ow) const {
Jisi Liu46e8ff62015-10-05 11:59:43 -0700142
Feng Xiaoe841bac2015-12-11 17:09:20 -0800143 const TypeRenderer* type_renderer = FindTypeRenderer(type.name());
144 if (type_renderer != NULL) {
145 return (*type_renderer)(this, type, name, ow);
146 }
Feng Xiaoe96ff302015-06-15 18:21:48 -0700147
148 const google::protobuf::Field* field = NULL;
149 string field_name;
150 // last_tag set to dummy value that is different from tag.
151 uint32 tag = stream_->ReadTag(), last_tag = tag + 1;
152
153 if (include_start_and_end) {
154 ow->StartObject(name);
155 }
156 while (tag != end_tag) {
157 if (tag != last_tag) { // Update field only if tag is changed.
158 last_tag = tag;
159 field = FindAndVerifyField(type, tag);
160 if (field != NULL) {
Feng Xiaoeee38b02015-08-22 18:25:48 -0700161 field_name = field->json_name();
Feng Xiaoe96ff302015-06-15 18:21:48 -0700162 }
163 }
164 if (field == NULL) {
165 // If we didn't find a field, skip this unknown tag.
166 // TODO(wpoon): Check return boolean value.
167 WireFormat::SkipField(stream_, tag, NULL);
168 tag = stream_->ReadTag();
169 continue;
170 }
171
172 if (field->cardinality() ==
173 google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
Feng Xiaoe841bac2015-12-11 17:09:20 -0800174 bool check_maps = true;
175
176 if (check_maps && IsMap(*field)) {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700177 ow->StartObject(field_name);
178 ASSIGN_OR_RETURN(tag, RenderMap(field, field_name, tag, ow));
179 ow->EndObject();
180 } else {
181 ASSIGN_OR_RETURN(tag, RenderList(field, field_name, tag, ow));
182 }
183 } else {
184 // Render the field.
185 RETURN_IF_ERROR(RenderField(field, field_name, ow));
186 tag = stream_->ReadTag();
187 }
188 }
189 if (include_start_and_end) {
190 ow->EndObject();
191 }
192 return Status::OK;
193}
194
195StatusOr<uint32> ProtoStreamObjectSource::RenderList(
196 const google::protobuf::Field* field, StringPiece name, uint32 list_tag,
197 ObjectWriter* ow) const {
198 uint32 tag_to_return = 0;
199 ow->StartList(name);
200 if (IsPackable(*field) &&
201 list_tag ==
202 WireFormatLite::MakeTag(field->number(),
203 WireFormatLite::WIRETYPE_LENGTH_DELIMITED)) {
204 RETURN_IF_ERROR(RenderPacked(field, ow));
205 // Since packed fields have a single tag, read another tag from stream to
206 // return.
207 tag_to_return = stream_->ReadTag();
208 } else {
209 do {
210 RETURN_IF_ERROR(RenderField(field, "", ow));
211 } while ((tag_to_return = stream_->ReadTag()) == list_tag);
212 }
213 ow->EndList();
214 return tag_to_return;
215}
216
217StatusOr<uint32> ProtoStreamObjectSource::RenderMap(
218 const google::protobuf::Field* field, StringPiece name, uint32 list_tag,
219 ObjectWriter* ow) const {
220 const google::protobuf::Type* field_type =
Feng Xiaoeee38b02015-08-22 18:25:48 -0700221 typeinfo_->GetTypeByTypeUrl(field->type_url());
Feng Xiaoe96ff302015-06-15 18:21:48 -0700222 uint32 tag_to_return = 0;
Feng Xiaoe841bac2015-12-11 17:09:20 -0800223 do {
224 // Render map entry message type.
225 uint32 buffer32;
226 stream_->ReadVarint32(&buffer32); // message length
227 int old_limit = stream_->PushLimit(buffer32);
228 string map_key;
229 for (uint32 tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) {
230 const google::protobuf::Field* field =
231 FindAndVerifyField(*field_type, tag);
232 if (field == NULL) {
233 WireFormat::SkipField(stream_, tag, NULL);
234 continue;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700235 }
Feng Xiaoe841bac2015-12-11 17:09:20 -0800236 // Map field numbers are key = 1 and value = 2
237 if (field->number() == 1) {
238 map_key = ReadFieldValueAsString(*field);
239 } else if (field->number() == 2) {
240 if (map_key.empty()) {
241 return Status(util::error::INTERNAL, "Map key must be non-empty");
242 }
243 RETURN_IF_ERROR(RenderField(field, map_key, ow));
244 }
Feng Xiaoe96ff302015-06-15 18:21:48 -0700245 }
Feng Xiaoe841bac2015-12-11 17:09:20 -0800246 stream_->PopLimit(old_limit);
247 } while ((tag_to_return = stream_->ReadTag()) == list_tag);
248 return tag_to_return;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700249}
250
251Status ProtoStreamObjectSource::RenderPacked(
252 const google::protobuf::Field* field, ObjectWriter* ow) const {
253 uint32 length;
254 stream_->ReadVarint32(&length);
255 int old_limit = stream_->PushLimit(length);
256 while (stream_->BytesUntilLimit() > 0) {
257 RETURN_IF_ERROR(RenderField(field, StringPiece(), ow));
258 }
259 stream_->PopLimit(old_limit);
260 return Status::OK;
261}
262
Feng Xiaoe96ff302015-06-15 18:21:48 -0700263Status ProtoStreamObjectSource::RenderTimestamp(
264 const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
265 StringPiece field_name, ObjectWriter* ow) {
266 pair<int64, int32> p = os->ReadSecondsAndNanos(type);
267 int64 seconds = p.first;
268 int32 nanos = p.second;
269 if (seconds > kMaxSeconds || seconds < kMinSeconds) {
270 return Status(
271 util::error::INTERNAL,
272 StrCat("Timestamp seconds exceeds limit for field: ", field_name));
273 }
274
275 if (nanos < 0 || nanos >= kNanosPerSecond) {
276 return Status(
277 util::error::INTERNAL,
278 StrCat("Timestamp nanos exceeds limit for field: ", field_name));
279 }
280
281 ow->RenderString(field_name,
282 ::google::protobuf::internal::FormatTime(seconds, nanos));
283
284 return Status::OK;
285}
286
287Status ProtoStreamObjectSource::RenderDuration(
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("Duration seconds exceeds limit for field: ", field_name));
297 }
298
299 if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
300 return Status(
301 util::error::INTERNAL,
302 StrCat("Duration nanos exceeds limit for field: ", field_name));
303 }
304
305 string sign = "";
306 if (seconds < 0) {
307 if (nanos > 0) {
308 return Status(util::error::INTERNAL,
Jisi Liu46e8ff62015-10-05 11:59:43 -0700309 StrCat("Duration nanos is non-negative, but seconds is "
310 "negative for field: ",
311 field_name));
Feng Xiaoe96ff302015-06-15 18:21:48 -0700312 }
313 sign = "-";
314 seconds = -seconds;
315 nanos = -nanos;
316 } else if (seconds == 0 && nanos < 0) {
317 sign = "-";
318 nanos = -nanos;
319 }
320 string formatted_duration = StringPrintf("%s%lld%ss", sign.c_str(), seconds,
321 FormatNanos(nanos).c_str());
322 ow->RenderString(field_name, formatted_duration);
323 return Status::OK;
324}
325
326Status ProtoStreamObjectSource::RenderDouble(const ProtoStreamObjectSource* os,
327 const google::protobuf::Type& type,
328 StringPiece field_name,
329 ObjectWriter* ow) {
330 uint32 tag = os->stream_->ReadTag();
331 uint64 buffer64 = 0; // default value of Double wrapper value
332 if (tag != 0) {
333 os->stream_->ReadLittleEndian64(&buffer64);
334 os->stream_->ReadTag();
335 }
336 ow->RenderDouble(field_name, bit_cast<double>(buffer64));
337 return Status::OK;
338}
339
340Status ProtoStreamObjectSource::RenderFloat(const ProtoStreamObjectSource* os,
341 const google::protobuf::Type& type,
342 StringPiece field_name,
343 ObjectWriter* ow) {
344 uint32 tag = os->stream_->ReadTag();
345 uint32 buffer32 = 0; // default value of Float wrapper value
346 if (tag != 0) {
347 os->stream_->ReadLittleEndian32(&buffer32);
348 os->stream_->ReadTag();
349 }
350 ow->RenderFloat(field_name, bit_cast<float>(buffer32));
351 return Status::OK;
352}
353
354Status ProtoStreamObjectSource::RenderInt64(const ProtoStreamObjectSource* os,
355 const google::protobuf::Type& type,
356 StringPiece field_name,
357 ObjectWriter* ow) {
358 uint32 tag = os->stream_->ReadTag();
359 uint64 buffer64 = 0; // default value of Int64 wrapper value
360 if (tag != 0) {
361 os->stream_->ReadVarint64(&buffer64);
362 os->stream_->ReadTag();
363 }
364 ow->RenderInt64(field_name, bit_cast<int64>(buffer64));
365 return Status::OK;
366}
367
368Status ProtoStreamObjectSource::RenderUInt64(const ProtoStreamObjectSource* os,
369 const google::protobuf::Type& type,
370 StringPiece field_name,
371 ObjectWriter* ow) {
372 uint32 tag = os->stream_->ReadTag();
373 uint64 buffer64 = 0; // default value of UInt64 wrapper value
374 if (tag != 0) {
375 os->stream_->ReadVarint64(&buffer64);
376 os->stream_->ReadTag();
377 }
378 ow->RenderUint64(field_name, bit_cast<uint64>(buffer64));
379 return Status::OK;
380}
381
382Status ProtoStreamObjectSource::RenderInt32(const ProtoStreamObjectSource* os,
383 const google::protobuf::Type& type,
384 StringPiece field_name,
385 ObjectWriter* ow) {
386 uint32 tag = os->stream_->ReadTag();
387 uint32 buffer32 = 0; // default value of Int32 wrapper value
388 if (tag != 0) {
389 os->stream_->ReadVarint32(&buffer32);
390 os->stream_->ReadTag();
391 }
392 ow->RenderInt32(field_name, bit_cast<int32>(buffer32));
393 return Status::OK;
394}
395
396Status ProtoStreamObjectSource::RenderUInt32(const ProtoStreamObjectSource* os,
397 const google::protobuf::Type& type,
398 StringPiece field_name,
399 ObjectWriter* ow) {
400 uint32 tag = os->stream_->ReadTag();
401 uint32 buffer32 = 0; // default value of UInt32 wrapper value
402 if (tag != 0) {
403 os->stream_->ReadVarint32(&buffer32);
404 os->stream_->ReadTag();
405 }
406 ow->RenderUint32(field_name, bit_cast<uint32>(buffer32));
407 return Status::OK;
408}
409
410Status ProtoStreamObjectSource::RenderBool(const ProtoStreamObjectSource* os,
411 const google::protobuf::Type& type,
412 StringPiece field_name,
413 ObjectWriter* ow) {
414 uint32 tag = os->stream_->ReadTag();
415 uint64 buffer64 = 0; // results in 'false' value as default, which is the
416 // default value of Bool wrapper
417 if (tag != 0) {
418 os->stream_->ReadVarint64(&buffer64);
419 os->stream_->ReadTag();
420 }
421 ow->RenderBool(field_name, buffer64 != 0);
422 return Status::OK;
423}
424
425Status ProtoStreamObjectSource::RenderString(const ProtoStreamObjectSource* os,
426 const google::protobuf::Type& type,
427 StringPiece field_name,
428 ObjectWriter* ow) {
429 uint32 tag = os->stream_->ReadTag();
430 uint32 buffer32;
431 string str; // default value of empty for String wrapper
432 if (tag != 0) {
433 os->stream_->ReadVarint32(&buffer32); // string size.
434 os->stream_->ReadString(&str, buffer32);
435 os->stream_->ReadTag();
436 }
437 ow->RenderString(field_name, str);
438 return Status::OK;
439}
440
441Status ProtoStreamObjectSource::RenderBytes(const ProtoStreamObjectSource* os,
442 const google::protobuf::Type& type,
443 StringPiece field_name,
444 ObjectWriter* ow) {
445 uint32 tag = os->stream_->ReadTag();
446 uint32 buffer32;
447 string str;
448 if (tag != 0) {
449 os->stream_->ReadVarint32(&buffer32);
450 os->stream_->ReadString(&str, buffer32);
451 os->stream_->ReadTag();
452 }
453 ow->RenderBytes(field_name, str);
454 return Status::OK;
455}
456
457Status ProtoStreamObjectSource::RenderStruct(const ProtoStreamObjectSource* os,
458 const google::protobuf::Type& type,
459 StringPiece field_name,
460 ObjectWriter* ow) {
461 const google::protobuf::Field* field = NULL;
462 uint32 tag = os->stream_->ReadTag();
463 ow->StartObject(field_name);
464 while (tag != 0) {
465 field = os->FindAndVerifyField(type, tag);
466 // google.protobuf.Struct has only one field that is a map. Hence we use
467 // RenderMap to render that field.
468 if (os->IsMap(*field)) {
469 ASSIGN_OR_RETURN(tag, os->RenderMap(field, field_name, tag, ow));
470 }
471 }
472 ow->EndObject();
473 return Status::OK;
474}
475
476Status ProtoStreamObjectSource::RenderStructValue(
477 const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
478 StringPiece field_name, ObjectWriter* ow) {
479 const google::protobuf::Field* field = NULL;
480 for (uint32 tag = os->stream_->ReadTag(); tag != 0;
481 tag = os->stream_->ReadTag()) {
482 field = os->FindAndVerifyField(type, tag);
483 if (field == NULL) {
484 WireFormat::SkipField(os->stream_, tag, NULL);
485 continue;
486 }
487 RETURN_IF_ERROR(os->RenderField(field, field_name, ow));
488 }
489 return Status::OK;
490}
491
492// TODO(skarvaje): Avoid code duplication of for loops and SkipField logic.
493Status ProtoStreamObjectSource::RenderStructListValue(
494 const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
495 StringPiece field_name, ObjectWriter* ow) {
496 uint32 tag = os->stream_->ReadTag();
497
498 // Render empty list when we find empty ListValue message.
499 if (tag == 0) {
500 ow->StartList(field_name);
501 ow->EndList();
502 return Status::OK;
503 }
504
505 while (tag != 0) {
506 const google::protobuf::Field* field = os->FindAndVerifyField(type, tag);
507 if (field == NULL) {
508 WireFormat::SkipField(os->stream_, tag, NULL);
509 tag = os->stream_->ReadTag();
510 continue;
511 }
512 ASSIGN_OR_RETURN(tag, os->RenderList(field, field_name, tag, ow));
513 }
514 return Status::OK;
515}
516
517Status ProtoStreamObjectSource::RenderAny(const ProtoStreamObjectSource* os,
518 const google::protobuf::Type& type,
519 StringPiece field_name,
520 ObjectWriter* ow) {
521 // An Any is of the form { string type_url = 1; bytes value = 2; }
522 uint32 tag;
523 string type_url;
524 string value;
525
526 // First read out the type_url and value from the proto stream
527 for (tag = os->stream_->ReadTag(); tag != 0; tag = os->stream_->ReadTag()) {
528 const google::protobuf::Field* field = os->FindAndVerifyField(type, tag);
529 if (field == NULL) {
530 WireFormat::SkipField(os->stream_, tag, NULL);
531 continue;
532 }
533 // 'type_url' has field number of 1 and 'value' has field number 2
534 // //google/protobuf/any.proto
535 if (field->number() == 1) {
536 // read type_url
537 uint32 type_url_size;
538 os->stream_->ReadVarint32(&type_url_size);
539 os->stream_->ReadString(&type_url, type_url_size);
540 } else if (field->number() == 2) {
541 // read value
542 uint32 value_size;
543 os->stream_->ReadVarint32(&value_size);
544 os->stream_->ReadString(&value, value_size);
545 }
546 }
547
548 // If there is no value, we don't lookup the type, we just output it (if
549 // present). If both type and value are empty we output an empty object.
550 if (value.empty()) {
551 ow->StartObject(field_name);
552 if (!type_url.empty()) {
553 ow->RenderString("@type", type_url);
554 }
555 ow->EndObject();
556 return util::Status::OK;
557 }
558
559 // If there is a value but no type, we cannot render it, so report an error.
560 if (type_url.empty()) {
561 // TODO(sven): Add an external message once those are ready.
562 return util::Status(util::error::INTERNAL,
563 "Invalid Any, the type_url is missing.");
564 }
565
566 util::StatusOr<const google::protobuf::Type*> resolved_type =
567 os->typeinfo_->ResolveTypeUrl(type_url);
568
569 if (!resolved_type.ok()) {
570 // Convert into an internal error, since this means the backend gave us
571 // an invalid response (missing or invalid type information).
572 return util::Status(util::error::INTERNAL,
573 resolved_type.status().error_message());
574 }
575 // nested_type cannot be null at this time.
576 const google::protobuf::Type* nested_type = resolved_type.ValueOrDie();
577
Feng Xiaoe96ff302015-06-15 18:21:48 -0700578 google::protobuf::io::ArrayInputStream zero_copy_stream(value.data(), value.size());
579 google::protobuf::io::CodedInputStream in_stream(&zero_copy_stream);
Feng Xiaoe841bac2015-12-11 17:09:20 -0800580 // We know the type so we can render it. Recursively parse the nested stream
581 // using a nested ProtoStreamObjectSource using our nested type information.
Feng Xiaoe96ff302015-06-15 18:21:48 -0700582 ProtoStreamObjectSource nested_os(&in_stream, os->typeinfo_, *nested_type);
583
584 // We manually call start and end object here so we can inject the @type.
585 ow->StartObject(field_name);
586 ow->RenderString("@type", type_url);
587 util::Status result =
588 nested_os.WriteMessage(nested_os.type_, "value", 0, false, ow);
589 ow->EndObject();
590 return result;
591}
592
593Status ProtoStreamObjectSource::RenderFieldMask(
594 const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
595 StringPiece field_name, ObjectWriter* ow) {
596 string combined;
597 uint32 buffer32;
598 uint32 paths_field_tag = 0;
599 for (uint32 tag = os->stream_->ReadTag(); tag != 0;
600 tag = os->stream_->ReadTag()) {
601 if (paths_field_tag == 0) {
602 const google::protobuf::Field* field = os->FindAndVerifyField(type, tag);
603 if (field != NULL && field->number() == 1 &&
604 field->name() == "paths") {
605 paths_field_tag = tag;
606 }
607 }
608 if (paths_field_tag != tag) {
609 return util::Status(util::error::INTERNAL,
610 "Invalid FieldMask, unexpected field.");
611 }
612 string str;
613 os->stream_->ReadVarint32(&buffer32); // string size.
614 os->stream_->ReadString(&str, buffer32);
615 if (!combined.empty()) {
616 combined.append(",");
617 }
618 combined.append(ConvertFieldMaskPath(str, &ToCamelCase));
619 }
620 ow->RenderString(field_name, combined);
621 return Status::OK;
622}
623
Jisi Liu46e8ff62015-10-05 11:59:43 -0700624
Feng Xiaoe96ff302015-06-15 18:21:48 -0700625hash_map<string, ProtoStreamObjectSource::TypeRenderer>*
Jisi Liu09778152015-08-25 22:01:12 -0700626 ProtoStreamObjectSource::renderers_ = NULL;
627GOOGLE_PROTOBUF_DECLARE_ONCE(source_renderers_init_);
628
629void ProtoStreamObjectSource::InitRendererMap() {
630 renderers_ = new hash_map<string, ProtoStreamObjectSource::TypeRenderer>();
631 (*renderers_)["google.protobuf.Timestamp"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -0700632 &ProtoStreamObjectSource::RenderTimestamp;
Jisi Liu09778152015-08-25 22:01:12 -0700633 (*renderers_)["google.protobuf.Duration"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -0700634 &ProtoStreamObjectSource::RenderDuration;
Jisi Liu09778152015-08-25 22:01:12 -0700635 (*renderers_)["google.protobuf.DoubleValue"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -0700636 &ProtoStreamObjectSource::RenderDouble;
Jisi Liu09778152015-08-25 22:01:12 -0700637 (*renderers_)["google.protobuf.FloatValue"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -0700638 &ProtoStreamObjectSource::RenderFloat;
Jisi Liu09778152015-08-25 22:01:12 -0700639 (*renderers_)["google.protobuf.Int64Value"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -0700640 &ProtoStreamObjectSource::RenderInt64;
Jisi Liu09778152015-08-25 22:01:12 -0700641 (*renderers_)["google.protobuf.UInt64Value"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -0700642 &ProtoStreamObjectSource::RenderUInt64;
Jisi Liu09778152015-08-25 22:01:12 -0700643 (*renderers_)["google.protobuf.Int32Value"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -0700644 &ProtoStreamObjectSource::RenderInt32;
Jisi Liu09778152015-08-25 22:01:12 -0700645 (*renderers_)["google.protobuf.UInt32Value"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -0700646 &ProtoStreamObjectSource::RenderUInt32;
Jisi Liu46e8ff62015-10-05 11:59:43 -0700647 (*renderers_)["google.protobuf.BoolValue"] =
648 &ProtoStreamObjectSource::RenderBool;
Jisi Liu09778152015-08-25 22:01:12 -0700649 (*renderers_)["google.protobuf.StringValue"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -0700650 &ProtoStreamObjectSource::RenderString;
Jisi Liu09778152015-08-25 22:01:12 -0700651 (*renderers_)["google.protobuf.BytesValue"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -0700652 &ProtoStreamObjectSource::RenderBytes;
Feng Xiaoe841bac2015-12-11 17:09:20 -0800653 (*renderers_)["google.protobuf.Any"] = &ProtoStreamObjectSource::RenderAny;
Jisi Liu46e8ff62015-10-05 11:59:43 -0700654 (*renderers_)["google.protobuf.Struct"] =
655 &ProtoStreamObjectSource::RenderStruct;
Jisi Liu09778152015-08-25 22:01:12 -0700656 (*renderers_)["google.protobuf.Value"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -0700657 &ProtoStreamObjectSource::RenderStructValue;
Jisi Liu09778152015-08-25 22:01:12 -0700658 (*renderers_)["google.protobuf.ListValue"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -0700659 &ProtoStreamObjectSource::RenderStructListValue;
Jisi Liu09778152015-08-25 22:01:12 -0700660 (*renderers_)["google.protobuf.FieldMask"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -0700661 &ProtoStreamObjectSource::RenderFieldMask;
Jisi Liu09778152015-08-25 22:01:12 -0700662 ::google::protobuf::internal::OnShutdown(&DeleteRendererMap);
663}
664
665void ProtoStreamObjectSource::DeleteRendererMap() {
666 delete ProtoStreamObjectSource::renderers_;
667 renderers_ = NULL;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700668}
669
670// static
671ProtoStreamObjectSource::TypeRenderer*
672ProtoStreamObjectSource::FindTypeRenderer(const string& type_url) {
Jisi Liu09778152015-08-25 22:01:12 -0700673 ::google::protobuf::GoogleOnceInit(&source_renderers_init_, &InitRendererMap);
674 return FindOrNull(*renderers_, type_url);
Feng Xiaoe96ff302015-06-15 18:21:48 -0700675}
676
677Status ProtoStreamObjectSource::RenderField(
678 const google::protobuf::Field* field, StringPiece field_name,
679 ObjectWriter* ow) const {
Feng Xiaoe841bac2015-12-11 17:09:20 -0800680 // Short-circuit message types as it tends to call WriteMessage recursively
681 // and ends up using a lot of stack space. Keep the stack usage of this
682 // message small in order to preserve stack space and not crash.
683 if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
684 uint32 buffer32;
685 stream_->ReadVarint32(&buffer32); // message length
686 int old_limit = stream_->PushLimit(buffer32);
687 // Get the nested message type for this field.
688 const google::protobuf::Type* type =
689 typeinfo_->GetTypeByTypeUrl(field->type_url());
690 if (type == NULL) {
691 return Status(util::error::INTERNAL,
692 StrCat("Invalid configuration. Could not find the type: ",
693 field->type_url()));
694 }
695
696 // Short-circuit any special type rendering to save call-stack space.
697 const TypeRenderer* type_renderer = FindTypeRenderer(type->name());
698
699 bool use_type_renderer = type_renderer != NULL;
700
701 if (use_type_renderer) {
702 RETURN_IF_ERROR((*type_renderer)(this, *type, field_name, ow));
703 } else {
704 RETURN_IF_ERROR(WriteMessage(*type, field_name, 0, true, ow));
705 }
706 if (!stream_->ConsumedEntireMessage()) {
707 return Status(util::error::INVALID_ARGUMENT,
708 "Nested protocol message not parsed in its entirety.");
709 }
710 stream_->PopLimit(old_limit);
711 } else {
712 // Render all other non-message types.
713 return RenderNonMessageField(field, field_name, ow);
714 }
715 return Status::OK;
716}
717
718Status ProtoStreamObjectSource::RenderNonMessageField(
719 const google::protobuf::Field* field, StringPiece field_name,
720 ObjectWriter* ow) const {
721 // Temporary buffers of different types.
722 uint32 buffer32;
723 uint64 buffer64;
724 string strbuffer;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700725 switch (field->kind()) {
726 case google::protobuf::Field_Kind_TYPE_BOOL: {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700727 stream_->ReadVarint64(&buffer64);
728 ow->RenderBool(field_name, buffer64 != 0);
729 break;
730 }
731 case google::protobuf::Field_Kind_TYPE_INT32: {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700732 stream_->ReadVarint32(&buffer32);
733 ow->RenderInt32(field_name, bit_cast<int32>(buffer32));
734 break;
735 }
736 case google::protobuf::Field_Kind_TYPE_INT64: {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700737 stream_->ReadVarint64(&buffer64);
738 ow->RenderInt64(field_name, bit_cast<int64>(buffer64));
739 break;
740 }
741 case google::protobuf::Field_Kind_TYPE_UINT32: {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700742 stream_->ReadVarint32(&buffer32);
743 ow->RenderUint32(field_name, bit_cast<uint32>(buffer32));
744 break;
745 }
746 case google::protobuf::Field_Kind_TYPE_UINT64: {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700747 stream_->ReadVarint64(&buffer64);
748 ow->RenderUint64(field_name, bit_cast<uint64>(buffer64));
749 break;
750 }
751 case google::protobuf::Field_Kind_TYPE_SINT32: {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700752 stream_->ReadVarint32(&buffer32);
753 ow->RenderInt32(field_name, WireFormatLite::ZigZagDecode32(buffer32));
754 break;
755 }
756 case google::protobuf::Field_Kind_TYPE_SINT64: {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700757 stream_->ReadVarint64(&buffer64);
758 ow->RenderInt64(field_name, WireFormatLite::ZigZagDecode64(buffer64));
759 break;
760 }
761 case google::protobuf::Field_Kind_TYPE_SFIXED32: {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700762 stream_->ReadLittleEndian32(&buffer32);
763 ow->RenderInt32(field_name, bit_cast<int32>(buffer32));
764 break;
765 }
766 case google::protobuf::Field_Kind_TYPE_SFIXED64: {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700767 stream_->ReadLittleEndian64(&buffer64);
768 ow->RenderInt64(field_name, bit_cast<int64>(buffer64));
769 break;
770 }
771 case google::protobuf::Field_Kind_TYPE_FIXED32: {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700772 stream_->ReadLittleEndian32(&buffer32);
773 ow->RenderUint32(field_name, bit_cast<uint32>(buffer32));
774 break;
775 }
776 case google::protobuf::Field_Kind_TYPE_FIXED64: {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700777 stream_->ReadLittleEndian64(&buffer64);
778 ow->RenderUint64(field_name, bit_cast<uint64>(buffer64));
779 break;
780 }
781 case google::protobuf::Field_Kind_TYPE_FLOAT: {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700782 stream_->ReadLittleEndian32(&buffer32);
783 ow->RenderFloat(field_name, bit_cast<float>(buffer32));
784 break;
785 }
786 case google::protobuf::Field_Kind_TYPE_DOUBLE: {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700787 stream_->ReadLittleEndian64(&buffer64);
788 ow->RenderDouble(field_name, bit_cast<double>(buffer64));
789 break;
790 }
791 case google::protobuf::Field_Kind_TYPE_ENUM: {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700792 stream_->ReadVarint32(&buffer32);
793
794 // If the field represents an explicit NULL value, render null.
795 if (field->type_url() == kStructNullValueTypeUrl) {
796 ow->RenderNull(field_name);
797 break;
798 }
799
800 // Get the nested enum type for this field.
801 // TODO(skarvaje): Avoid string manipulation. Find ways to speed this
802 // up.
Feng Xiaoeee38b02015-08-22 18:25:48 -0700803 const google::protobuf::Enum* en =
804 typeinfo_->GetEnumByTypeUrl(field->type_url());
Feng Xiaoe96ff302015-06-15 18:21:48 -0700805 // Lookup the name of the enum, and render that. Skips unknown enums.
806 if (en != NULL) {
807 const google::protobuf::EnumValue* enum_value =
808 FindEnumValueByNumber(*en, buffer32);
809 if (enum_value != NULL) {
810 ow->RenderString(field_name, enum_value->name());
811 }
812 } else {
Benjamin Barenblata2ce9cb2015-10-30 14:05:24 -0400813 GOOGLE_LOG(INFO) << "Unknown enum skipped: " << field->type_url();
Feng Xiaoe96ff302015-06-15 18:21:48 -0700814 }
815 break;
816 }
817 case google::protobuf::Field_Kind_TYPE_STRING: {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700818 stream_->ReadVarint32(&buffer32); // string size.
Feng Xiaoe841bac2015-12-11 17:09:20 -0800819 stream_->ReadString(&strbuffer, buffer32);
820 ow->RenderString(field_name, strbuffer);
Feng Xiaoe96ff302015-06-15 18:21:48 -0700821 break;
822 }
823 case google::protobuf::Field_Kind_TYPE_BYTES: {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700824 stream_->ReadVarint32(&buffer32); // bytes size.
Feng Xiaoe841bac2015-12-11 17:09:20 -0800825 stream_->ReadString(&strbuffer, buffer32);
826 ow->RenderBytes(field_name, strbuffer);
Feng Xiaoe96ff302015-06-15 18:21:48 -0700827 break;
828 }
829 default:
830 break;
831 }
832 return Status::OK;
833}
834
835// TODO(skarvaje): Fix this to avoid code duplication.
836const string ProtoStreamObjectSource::ReadFieldValueAsString(
837 const google::protobuf::Field& field) const {
838 string result;
839 switch (field.kind()) {
840 case google::protobuf::Field_Kind_TYPE_BOOL: {
841 uint64 buffer64;
842 stream_->ReadVarint64(&buffer64);
843 result = buffer64 != 0 ? "true" : "false";
844 break;
845 }
846 case google::protobuf::Field_Kind_TYPE_INT32: {
847 uint32 buffer32;
848 stream_->ReadVarint32(&buffer32);
849 result = SimpleItoa(bit_cast<int32>(buffer32));
850 break;
851 }
852 case google::protobuf::Field_Kind_TYPE_INT64: {
853 uint64 buffer64;
854 stream_->ReadVarint64(&buffer64);
855 result = SimpleItoa(bit_cast<int64>(buffer64));
856 break;
857 }
858 case google::protobuf::Field_Kind_TYPE_UINT32: {
859 uint32 buffer32;
860 stream_->ReadVarint32(&buffer32);
861 result = SimpleItoa(bit_cast<uint32>(buffer32));
862 break;
863 }
864 case google::protobuf::Field_Kind_TYPE_UINT64: {
865 uint64 buffer64;
866 stream_->ReadVarint64(&buffer64);
867 result = SimpleItoa(bit_cast<uint64>(buffer64));
868 break;
869 }
870 case google::protobuf::Field_Kind_TYPE_SINT32: {
871 uint32 buffer32;
872 stream_->ReadVarint32(&buffer32);
873 result = SimpleItoa(WireFormatLite::ZigZagDecode32(buffer32));
874 break;
875 }
876 case google::protobuf::Field_Kind_TYPE_SINT64: {
877 uint64 buffer64;
878 stream_->ReadVarint64(&buffer64);
879 result = SimpleItoa(WireFormatLite::ZigZagDecode64(buffer64));
880 break;
881 }
882 case google::protobuf::Field_Kind_TYPE_SFIXED32: {
883 uint32 buffer32;
884 stream_->ReadLittleEndian32(&buffer32);
885 result = SimpleItoa(bit_cast<int32>(buffer32));
886 break;
887 }
888 case google::protobuf::Field_Kind_TYPE_SFIXED64: {
889 uint64 buffer64;
890 stream_->ReadLittleEndian64(&buffer64);
891 result = SimpleItoa(bit_cast<int64>(buffer64));
892 break;
893 }
894 case google::protobuf::Field_Kind_TYPE_FIXED32: {
895 uint32 buffer32;
896 stream_->ReadLittleEndian32(&buffer32);
897 result = SimpleItoa(bit_cast<uint32>(buffer32));
898 break;
899 }
900 case google::protobuf::Field_Kind_TYPE_FIXED64: {
901 uint64 buffer64;
902 stream_->ReadLittleEndian64(&buffer64);
903 result = SimpleItoa(bit_cast<uint64>(buffer64));
904 break;
905 }
906 case google::protobuf::Field_Kind_TYPE_FLOAT: {
907 uint32 buffer32;
908 stream_->ReadLittleEndian32(&buffer32);
909 result = SimpleFtoa(bit_cast<float>(buffer32));
910 break;
911 }
912 case google::protobuf::Field_Kind_TYPE_DOUBLE: {
913 uint64 buffer64;
914 stream_->ReadLittleEndian64(&buffer64);
915 result = SimpleDtoa(bit_cast<double>(buffer64));
916 break;
917 }
918 case google::protobuf::Field_Kind_TYPE_ENUM: {
919 uint32 buffer32;
920 stream_->ReadVarint32(&buffer32);
921 // Get the nested enum type for this field.
922 // TODO(skarvaje): Avoid string manipulation. Find ways to speed this
923 // up.
Feng Xiaoeee38b02015-08-22 18:25:48 -0700924 const google::protobuf::Enum* en =
925 typeinfo_->GetEnumByTypeUrl(field.type_url());
Feng Xiaoe96ff302015-06-15 18:21:48 -0700926 // Lookup the name of the enum, and render that. Skips unknown enums.
927 if (en != NULL) {
928 const google::protobuf::EnumValue* enum_value =
929 FindEnumValueByNumber(*en, buffer32);
930 if (enum_value != NULL) {
931 result = enum_value->name();
932 }
933 }
934 break;
935 }
936 case google::protobuf::Field_Kind_TYPE_STRING: {
937 uint32 buffer32;
938 stream_->ReadVarint32(&buffer32); // string size.
939 stream_->ReadString(&result, buffer32);
940 break;
941 }
942 case google::protobuf::Field_Kind_TYPE_BYTES: {
943 uint32 buffer32;
944 stream_->ReadVarint32(&buffer32); // bytes size.
945 stream_->ReadString(&result, buffer32);
946 break;
947 }
948 default:
949 break;
950 }
951 return result;
952}
953
954// Field is a map if it is a repeated message and it has an option "map_type".
955// TODO(skarvaje): Consider pre-computing the IsMap() into Field directly.
956bool ProtoStreamObjectSource::IsMap(
957 const google::protobuf::Field& field) const {
958 const google::protobuf::Type* field_type =
Feng Xiaoeee38b02015-08-22 18:25:48 -0700959 typeinfo_->GetTypeByTypeUrl(field.type_url());
Feng Xiaoe96ff302015-06-15 18:21:48 -0700960
961 // TODO(xiaofeng): Unify option names.
962 return field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE &&
963 (GetBoolOptionOrDefault(field_type->options(),
964 "google.protobuf.MessageOptions.map_entry", false) ||
965 GetBoolOptionOrDefault(field_type->options(), "map_entry", false));
966}
967
968std::pair<int64, int32> ProtoStreamObjectSource::ReadSecondsAndNanos(
969 const google::protobuf::Type& type) const {
970 uint64 seconds = 0;
971 uint32 nanos = 0;
972 uint32 tag = 0;
973 int64 signed_seconds = 0;
Jisi Liu46e8ff62015-10-05 11:59:43 -0700974 int32 signed_nanos = 0;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700975
976 for (tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) {
977 const google::protobuf::Field* field = FindAndVerifyField(type, tag);
978 if (field == NULL) {
979 WireFormat::SkipField(stream_, tag, NULL);
980 continue;
981 }
982 // 'seconds' has field number of 1 and 'nanos' has field number 2
983 // //google/protobuf/timestamp.proto & duration.proto
984 if (field->number() == 1) {
985 // read seconds
986 stream_->ReadVarint64(&seconds);
987 signed_seconds = bit_cast<int64>(seconds);
988 } else if (field->number() == 2) {
989 // read nanos
990 stream_->ReadVarint32(&nanos);
991 signed_nanos = bit_cast<int32>(nanos);
992 }
993 }
994 return std::pair<int64, int32>(signed_seconds, signed_nanos);
995}
996
997namespace {
998// TODO(skarvaje): Speed this up by not doing a linear scan.
999const google::protobuf::Field* FindFieldByNumber(
1000 const google::protobuf::Type& type, int number) {
1001 for (int i = 0; i < type.fields_size(); ++i) {
1002 if (type.fields(i).number() == number) {
1003 return &type.fields(i);
1004 }
1005 }
1006 return NULL;
1007}
1008
1009// TODO(skarvaje): Replace FieldDescriptor by implementing IsTypePackable()
1010// using tech Field.
1011bool IsPackable(const google::protobuf::Field& field) {
1012 return field.cardinality() ==
1013 google::protobuf::Field_Cardinality_CARDINALITY_REPEATED &&
1014 google::protobuf::FieldDescriptor::IsTypePackable(
1015 static_cast<google::protobuf::FieldDescriptor::Type>(field.kind()));
1016}
1017
1018// TODO(skarvaje): Speed this up by not doing a linear scan.
1019const google::protobuf::EnumValue* FindEnumValueByNumber(
1020 const google::protobuf::Enum& tech_enum, int number) {
1021 for (int i = 0; i < tech_enum.enumvalue_size(); ++i) {
1022 const google::protobuf::EnumValue& ev = tech_enum.enumvalue(i);
1023 if (ev.number() == number) {
1024 return &ev;
1025 }
1026 }
1027 return NULL;
1028}
1029
1030// TODO(skarvaje): Look into optimizing this by not doing computation on
1031// double.
1032const string FormatNanos(uint32 nanos) {
1033 const char* format =
1034 (nanos % 1000 != 0) ? "%.9f" : (nanos % 1000000 != 0) ? "%.6f" : "%.3f";
1035 string formatted =
1036 StringPrintf(format, static_cast<double>(nanos) / kNanosPerSecond);
1037 // remove the leading 0 before decimal.
1038 return formatted.substr(1);
1039}
1040} // namespace
1041
1042} // namespace converter
1043} // namespace util
1044} // namespace protobuf
1045} // namespace google