blob: 94ddb4287efeae259f07dd9d11990e3e217a7119 [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_objectwriter.h>
32
33#include <functional>
34#include <stack>
35
Jisi Liu46e8ff62015-10-05 11:59:43 -070036#include <google/protobuf/stubs/once.h>
Feng Xiaoe96ff302015-06-15 18:21:48 -070037#include <google/protobuf/stubs/time.h>
38#include <google/protobuf/wire_format_lite.h>
39#include <google/protobuf/util/internal/field_mask_utility.h>
40#include <google/protobuf/util/internal/object_location_tracker.h>
41#include <google/protobuf/util/internal/constants.h>
42#include <google/protobuf/util/internal/utility.h>
43#include <google/protobuf/stubs/strutil.h>
44#include <google/protobuf/stubs/map_util.h>
45#include <google/protobuf/stubs/statusor.h>
46
47
48namespace google {
49namespace protobuf {
50namespace util {
51namespace converter {
52
53using google::protobuf::internal::WireFormatLite;
Feng Xiaoe96ff302015-06-15 18:21:48 -070054using util::error::INVALID_ARGUMENT;
55using util::Status;
56using util::StatusOr;
57
58
59ProtoStreamObjectWriter::ProtoStreamObjectWriter(
60 TypeResolver* type_resolver, const google::protobuf::Type& type,
Jisi Liu3b3c8ab2016-03-30 11:39:59 -070061 strings::ByteSink* output, ErrorListener* listener,
62 const ProtoStreamObjectWriter::Options& options)
Feng Xiaoe841bac2015-12-11 17:09:20 -080063 : ProtoWriter(type_resolver, type, output, listener),
64 master_type_(type),
Jisi Liu3b3c8ab2016-03-30 11:39:59 -070065 current_(NULL),
66 options_(options) {}
Feng Xiaoe96ff302015-06-15 18:21:48 -070067
68ProtoStreamObjectWriter::ProtoStreamObjectWriter(
Feng Xiaoeee38b02015-08-22 18:25:48 -070069 const TypeInfo* typeinfo, const google::protobuf::Type& type,
Feng Xiaoe96ff302015-06-15 18:21:48 -070070 strings::ByteSink* output, ErrorListener* listener)
Feng Xiaoe841bac2015-12-11 17:09:20 -080071 : ProtoWriter(typeinfo, type, output, listener),
72 master_type_(type),
Jisi Liu3b3c8ab2016-03-30 11:39:59 -070073 current_(NULL),
74 options_(ProtoStreamObjectWriter::Options::Defaults()) {}
Feng Xiaoe96ff302015-06-15 18:21:48 -070075
76ProtoStreamObjectWriter::~ProtoStreamObjectWriter() {
Feng Xiaoe841bac2015-12-11 17:09:20 -080077 if (current_ == NULL) return;
Feng Xiaoeee38b02015-08-22 18:25:48 -070078 // Cleanup explicitly in order to avoid destructor stack overflow when input
79 // is deeply nested.
80 // Cast to BaseElement to avoid doing additional checks (like missing fields)
81 // during pop().
82 google::protobuf::scoped_ptr<BaseElement> element(
Feng Xiaoe841bac2015-12-11 17:09:20 -080083 static_cast<BaseElement*>(current_.get())->pop<BaseElement>());
Feng Xiaoeee38b02015-08-22 18:25:48 -070084 while (element != NULL) {
85 element.reset(element->pop<BaseElement>());
86 }
Feng Xiaoe96ff302015-06-15 18:21:48 -070087}
88
89namespace {
Feng Xiaoe96ff302015-06-15 18:21:48 -070090// Utility method to split a string representation of Timestamp or Duration and
91// return the parts.
92void SplitSecondsAndNanos(StringPiece input, StringPiece* seconds,
93 StringPiece* nanos) {
94 size_t idx = input.rfind('.');
95 if (idx != string::npos) {
96 *seconds = input.substr(0, idx);
97 *nanos = input.substr(idx + 1);
98 } else {
99 *seconds = input;
100 *nanos = StringPiece();
101 }
102}
103
Feng Xiaoe841bac2015-12-11 17:09:20 -0800104Status GetNanosFromStringPiece(StringPiece s_nanos,
105 const char* parse_failure_message,
106 const char* exceeded_limit_message,
107 int32* nanos) {
108 *nanos = 0;
109
110 // Count the number of leading 0s and consume them.
111 int num_leading_zeros = 0;
112 while (s_nanos.Consume("0")) {
113 num_leading_zeros++;
114 }
115 int32 i_nanos = 0;
116 // 's_nanos' contains fractional seconds -- i.e. 'nanos' is equal to
117 // "0." + s_nanos.ToString() seconds. An int32 is used for the
118 // conversion to 'nanos', rather than a double, so that there is no
119 // loss of precision.
120 if (!s_nanos.empty() && !safe_strto32(s_nanos.ToString(), &i_nanos)) {
121 return Status(INVALID_ARGUMENT, parse_failure_message);
122 }
123 if (i_nanos > kNanosPerSecond || i_nanos < 0) {
124 return Status(INVALID_ARGUMENT, exceeded_limit_message);
125 }
126 // s_nanos should only have digits. No whitespace.
127 if (s_nanos.find_first_not_of("0123456789") != StringPiece::npos) {
128 return Status(INVALID_ARGUMENT, parse_failure_message);
129 }
130
131 if (i_nanos > 0) {
132 // 'scale' is the number of digits to the right of the decimal
133 // point in "0." + s_nanos.ToString()
134 int32 scale = num_leading_zeros + s_nanos.size();
135 // 'conversion' converts i_nanos into nanoseconds.
136 // conversion = kNanosPerSecond / static_cast<int32>(std::pow(10, scale))
137 // For efficiency, we precompute the conversion factor.
138 int32 conversion = 0;
139 switch (scale) {
140 case 1:
141 conversion = 100000000;
142 break;
143 case 2:
144 conversion = 10000000;
145 break;
146 case 3:
147 conversion = 1000000;
148 break;
149 case 4:
150 conversion = 100000;
151 break;
152 case 5:
153 conversion = 10000;
154 break;
155 case 6:
156 conversion = 1000;
157 break;
158 case 7:
159 conversion = 100;
160 break;
161 case 8:
162 conversion = 10;
163 break;
164 case 9:
165 conversion = 1;
166 break;
167 default:
168 return Status(INVALID_ARGUMENT, exceeded_limit_message);
169 }
170 *nanos = i_nanos * conversion;
171 }
172
173 return Status::OK;
174}
175
Feng Xiaoe96ff302015-06-15 18:21:48 -0700176} // namespace
177
178ProtoStreamObjectWriter::AnyWriter::AnyWriter(ProtoStreamObjectWriter* parent)
179 : parent_(parent),
180 ow_(),
181 invalid_(false),
182 data_(),
183 output_(&data_),
184 depth_(0),
185 has_injected_value_message_(false) {}
186
187ProtoStreamObjectWriter::AnyWriter::~AnyWriter() {}
188
189void ProtoStreamObjectWriter::AnyWriter::StartObject(StringPiece name) {
190 ++depth_;
191 // If an object writer is absent, that means we have not called StartAny()
192 // before reaching here. This is an invalid state. StartAny() gets called
193 // whenever we see an "@type" being rendered (see AnyWriter::RenderDataPiece).
194 if (ow_ == NULL) {
195 // Make sure we are not already in an invalid state. This avoids making
196 // multiple unnecessary InvalidValue calls.
197 if (!invalid_) {
198 parent_->InvalidValue("Any",
199 StrCat("Missing or invalid @type for any field in ",
200 parent_->master_type_.name()));
201 invalid_ = true;
202 }
203 } else if (!has_injected_value_message_ || depth_ != 1 || name != "value") {
204 // We don't propagate to ow_ StartObject("value") calls for nested Anys or
205 // Struct at depth 1 as they are nested one level deep with an injected
206 // "value" field.
207 ow_->StartObject(name);
208 }
209}
210
211bool ProtoStreamObjectWriter::AnyWriter::EndObject() {
212 --depth_;
213 // As long as depth_ >= 0, we know we haven't reached the end of Any.
214 // Propagate these EndObject() calls to the contained ow_. If we are in a
215 // nested Any or Struct type, ignore the second to last EndObject call (depth_
216 // == -1)
217 if (ow_ != NULL && (!has_injected_value_message_ || depth_ >= 0)) {
218 ow_->EndObject();
219 }
220 // A negative depth_ implies that we have reached the end of Any
221 // object. Now we write out its contents.
222 if (depth_ < 0) {
223 WriteAny();
224 return false;
225 }
226 return true;
227}
228
229void ProtoStreamObjectWriter::AnyWriter::StartList(StringPiece name) {
230 ++depth_;
231 // We expect ow_ to be present as this call only makes sense inside an Any.
232 if (ow_ == NULL) {
233 if (!invalid_) {
234 parent_->InvalidValue("Any",
235 StrCat("Missing or invalid @type for any field in ",
236 parent_->master_type_.name()));
237 invalid_ = true;
238 }
239 } else {
240 ow_->StartList(name);
241 }
242}
243
244void ProtoStreamObjectWriter::AnyWriter::EndList() {
245 --depth_;
246 if (depth_ < 0) {
247 GOOGLE_LOG(DFATAL) << "Mismatched EndList found, should not be possible";
248 depth_ = 0;
249 }
250 // We don't write an error on the close, only on the open
251 if (ow_ != NULL) {
252 ow_->EndList();
253 }
254}
255
256void ProtoStreamObjectWriter::AnyWriter::RenderDataPiece(
257 StringPiece name, const DataPiece& value) {
258 // Start an Any only at depth_ 0. Other RenderDataPiece calls with "@type"
259 // should go to the contained ow_ as they indicate nested Anys.
260 if (depth_ == 0 && ow_ == NULL && name == "@type") {
261 StartAny(value);
262 } else if (ow_ == NULL) {
263 if (!invalid_) {
264 parent_->InvalidValue("Any",
265 StrCat("Missing or invalid @type for any field in ",
266 parent_->master_type_.name()));
267 invalid_ = true;
268 }
269 } else {
270 // Check to see if the data needs to be rendered with well-known-type
271 // renderer.
272 const TypeRenderer* type_renderer =
273 FindTypeRenderer(GetFullTypeWithUrl(ow_->master_type_.name()));
274 if (type_renderer) {
Jisi Liu46e8ff62015-10-05 11:59:43 -0700275 Status status = (*type_renderer)(ow_.get(), value);
276 if (!status.ok()) ow_->InvalidValue("Any", status.error_message());
Feng Xiaoe96ff302015-06-15 18:21:48 -0700277 } else {
278 ow_->RenderDataPiece(name, value);
279 }
280 }
281}
282
283void ProtoStreamObjectWriter::AnyWriter::StartAny(const DataPiece& value) {
284 // Figure out the type url. This is a copy-paste from WriteString but we also
285 // need the value, so we can't just call through to that.
286 if (value.type() == DataPiece::TYPE_STRING) {
287 type_url_ = value.str().ToString();
288 } else {
289 StatusOr<string> s = value.ToString();
290 if (!s.ok()) {
291 parent_->InvalidValue("String", s.status().error_message());
292 invalid_ = true;
293 return;
294 }
295 type_url_ = s.ValueOrDie();
296 }
297 // Resolve the type url, and report an error if we failed to resolve it.
298 StatusOr<const google::protobuf::Type*> resolved_type =
Feng Xiaoe841bac2015-12-11 17:09:20 -0800299 parent_->typeinfo()->ResolveTypeUrl(type_url_);
Feng Xiaoe96ff302015-06-15 18:21:48 -0700300 if (!resolved_type.ok()) {
301 parent_->InvalidValue("Any", resolved_type.status().error_message());
302 invalid_ = true;
303 return;
304 }
305 // At this point, type is never null.
306 const google::protobuf::Type* type = resolved_type.ValueOrDie();
307
308 // If this is the case of an Any in an Any or Struct in an Any, we need to
309 // expect a StartObject call with "value" while we're at depth_ 0, which we
310 // should ignore (not propagate to our nested object writer). We also need to
311 // ignore the second-to-last EndObject call, and not propagate that either.
312 if (type->name() == kAnyType || type->name() == kStructType) {
313 has_injected_value_message_ = true;
314 }
315
316 // Create our object writer and initialize it with the first StartObject
317 // call.
Feng Xiaoe841bac2015-12-11 17:09:20 -0800318 ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo(), *type, &output_,
319 parent_->listener()));
Feng Xiaoe96ff302015-06-15 18:21:48 -0700320 ow_->StartObject("");
321}
322
323void ProtoStreamObjectWriter::AnyWriter::WriteAny() {
324 if (ow_ == NULL) {
325 // If we had no object writer, we never got any content, so just return
326 // immediately, which is equivalent to writing an empty Any.
327 return;
328 }
329 // Render the type_url and value fields directly to the stream.
330 // type_url has tag 1 and value has tag 2.
Feng Xiaoe841bac2015-12-11 17:09:20 -0800331 WireFormatLite::WriteString(1, type_url_, parent_->stream());
Feng Xiaoe96ff302015-06-15 18:21:48 -0700332 if (!data_.empty()) {
Feng Xiaoe841bac2015-12-11 17:09:20 -0800333 WireFormatLite::WriteBytes(2, data_, parent_->stream());
Feng Xiaoe96ff302015-06-15 18:21:48 -0700334 }
335}
336
Feng Xiaoe841bac2015-12-11 17:09:20 -0800337ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter* enclosing,
338 ItemType item_type, bool is_placeholder,
339 bool is_list)
Feng Xiaoe96ff302015-06-15 18:21:48 -0700340 : BaseElement(NULL),
341 ow_(enclosing),
342 any_(),
Feng Xiaoe841bac2015-12-11 17:09:20 -0800343 item_type_(item_type),
344 is_placeholder_(is_placeholder),
345 is_list_(is_list) {
346 if (item_type_ == ANY) {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700347 any_.reset(new AnyWriter(ow_));
348 }
349}
350
Feng Xiaoe841bac2015-12-11 17:09:20 -0800351ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter::Item* parent,
352 ItemType item_type, bool is_placeholder,
353 bool is_list)
Feng Xiaoe96ff302015-06-15 18:21:48 -0700354 : BaseElement(parent),
355 ow_(this->parent()->ow_),
356 any_(),
Feng Xiaoe841bac2015-12-11 17:09:20 -0800357 item_type_(item_type),
358 is_placeholder_(is_placeholder),
359 is_list_(is_list) {
360 if (item_type == ANY) {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700361 any_.reset(new AnyWriter(ow_));
362 }
363}
364
Feng Xiaoe841bac2015-12-11 17:09:20 -0800365bool ProtoStreamObjectWriter::Item::InsertMapKeyIfNotPresent(
Jisi Liu46e8ff62015-10-05 11:59:43 -0700366 StringPiece map_key) {
Feng Xiao9659ea92015-11-02 12:39:27 -0800367 return InsertIfNotPresent(&map_keys_, map_key.ToString());
Jisi Liu46e8ff62015-10-05 11:59:43 -0700368}
369
Feng Xiaoe96ff302015-06-15 18:21:48 -0700370ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject(
371 StringPiece name) {
Feng Xiaoe841bac2015-12-11 17:09:20 -0800372 if (invalid_depth() > 0) {
373 IncrementInvalidDepth();
374 return this;
375 }
376
377 // Starting the root message. Create the root Item and return.
378 // ANY message type does not need special handling, just set the ItemType
379 // to ANY.
380 if (current_ == NULL) {
381 ProtoWriter::StartObject(name);
382 current_.reset(new Item(
383 this, master_type_.name() == kAnyType ? Item::ANY : Item::MESSAGE,
384 false, false));
Feng Xiaoe96ff302015-06-15 18:21:48 -0700385
386 // If master type is a special type that needs extra values to be written to
387 // stream, we write those values.
388 if (master_type_.name() == kStructType) {
Feng Xiaoe841bac2015-12-11 17:09:20 -0800389 // Struct has a map<string, Value> field called "fields".
390 // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
391 // "fields": [
392 Push("fields", Item::MAP, true, true);
Jisi Liu46e8ff62015-10-05 11:59:43 -0700393 return this;
394 }
395
Feng Xiaoe841bac2015-12-11 17:09:20 -0800396 if (master_type_.name() == kStructValueType) {
397 // We got a StartObject call with google.protobuf.Value field. The only
398 // object within that type is a struct type. So start a struct.
399 //
400 // The struct field in Value type is named "struct_value"
401 // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
402 // Also start the map field "fields" within the struct.
403 // "struct_value": {
404 // "fields": [
405 Push("struct_value", Item::MESSAGE, true, false);
406 Push("fields", Item::MAP, true, true);
407 return this;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700408 }
Feng Xiaoe841bac2015-12-11 17:09:20 -0800409
410 if (master_type_.name() == kStructListValueType) {
411 InvalidValue(kStructListValueType,
412 "Cannot start root message with ListValue.");
413 }
414
Feng Xiaoe96ff302015-06-15 18:21:48 -0700415 return this;
416 }
417
Feng Xiaoe841bac2015-12-11 17:09:20 -0800418 // Send all ANY events to AnyWriter.
419 if (current_->IsAny()) {
420 current_->any()->StartObject(name);
Feng Xiaoe96ff302015-06-15 18:21:48 -0700421 return this;
422 }
423
Feng Xiaoe841bac2015-12-11 17:09:20 -0800424 // If we are within a map, we render name as keys and send StartObject to the
425 // value field.
426 if (current_->IsMap()) {
427 if (!ValidMapKey(name)) {
428 IncrementInvalidDepth();
429 return this;
430 }
431
432 // Map is a repeated field of message type with a "key" and a "value" field.
433 // https://developers.google.com/protocol-buffers/docs/proto3?hl=en#maps
434 // message MapFieldEntry {
435 // key_type key = 1;
436 // value_type value = 2;
437 // }
438 //
439 // repeated MapFieldEntry map_field = N;
440 //
441 // That means, we render the following element within a list (hence no
442 // name):
443 // { "key": "<name>", "value": {
444 Push("", Item::MESSAGE, false, false);
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700445 ProtoWriter::RenderDataPiece("key",
446 DataPiece(name, use_strict_base64_decoding()));
Feng Xiaoe841bac2015-12-11 17:09:20 -0800447 Push("value", Item::MESSAGE, true, false);
448
449 // Make sure we are valid so far after starting map fields.
450 if (invalid_depth() > 0) return this;
451
452 // If top of stack is g.p.Struct type, start the struct the map field within
453 // it.
454 if (element() != NULL && IsStruct(*element()->parent_field())) {
455 // Render "fields": [
456 Push("fields", Item::MAP, true, true);
457 return this;
458 }
459
460 // If top of stack is g.p.Value type, start the Struct within it.
461 if (element() != NULL && IsStructValue(*element()->parent_field())) {
462 // Render
463 // "struct_value": {
464 // "fields": [
465 Push("struct_value", Item::MESSAGE, true, false);
466 Push("fields", Item::MAP, true, true);
467 }
Feng Xiaoeee38b02015-08-22 18:25:48 -0700468 return this;
469 }
470
Feng Xiaoe841bac2015-12-11 17:09:20 -0800471 const google::protobuf::Field* field = BeginNamed(name, false);
472 if (field == NULL) return this;
473
474 if (IsStruct(*field)) {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700475 // Start a struct object.
Feng Xiaoe841bac2015-12-11 17:09:20 -0800476 // Render
477 // "<name>": {
478 // "fields": {
479 Push(name, Item::MESSAGE, false, false);
480 Push("fields", Item::MAP, true, true);
481 return this;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700482 }
Feng Xiaoe841bac2015-12-11 17:09:20 -0800483
484 if (IsStructValue(*field)) {
485 // We got a StartObject call with google.protobuf.Value field. The only
486 // object within that type is a struct type. So start a struct.
487 // Render
488 // "<name>": {
489 // "struct_value": {
490 // "fields": {
491 Push(name, Item::MESSAGE, false, false);
492 Push("struct_value", Item::MESSAGE, true, false);
493 Push("fields", Item::MAP, true, true);
494 return this;
495 }
496
497 if (IsMap(*field)) {
498 // Begin a map. A map is triggered by a StartObject() call if the current
499 // field has a map type.
500 // A map type is always repeated, hence set is_list to true.
501 // Render
502 // "<name>": [
503 Push(name, Item::MAP, false, true);
504 return this;
505 }
506
507 // A regular message type. Pass it directly to ProtoWriter.
508 // Render
509 // "<name>": {
510 Push(name, IsAny(*field) ? Item::ANY : Item::MESSAGE, false, false);
Feng Xiaoe96ff302015-06-15 18:21:48 -0700511 return this;
512}
513
Feng Xiaoe96ff302015-06-15 18:21:48 -0700514ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndObject() {
Feng Xiaoe841bac2015-12-11 17:09:20 -0800515 if (invalid_depth() > 0) {
516 DecrementInvalidDepth();
Feng Xiaoe96ff302015-06-15 18:21:48 -0700517 return this;
518 }
Feng Xiaoe841bac2015-12-11 17:09:20 -0800519
520 if (current_ == NULL) return this;
521
522 if (current_->IsAny()) {
523 if (current_->any()->EndObject()) return this;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700524 }
525
Feng Xiaoe841bac2015-12-11 17:09:20 -0800526 Pop();
Feng Xiaoe96ff302015-06-15 18:21:48 -0700527
Feng Xiaoe96ff302015-06-15 18:21:48 -0700528 return this;
529}
530
531ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) {
Feng Xiaoe841bac2015-12-11 17:09:20 -0800532 if (invalid_depth() > 0) {
533 IncrementInvalidDepth();
534 return this;
535 }
536
Feng Xiaoe96ff302015-06-15 18:21:48 -0700537 // Since we cannot have a top-level repeated item in protobuf, the only way
Feng Xiaoe841bac2015-12-11 17:09:20 -0800538 // this is valid is if we start a special type google.protobuf.ListValue or
539 // google.protobuf.Value.
540 if (current_ == NULL) {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700541 if (!name.empty()) {
542 InvalidName(name, "Root element should not be named.");
Feng Xiaoe841bac2015-12-11 17:09:20 -0800543 IncrementInvalidDepth();
544 return this;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700545 }
Feng Xiaoe96ff302015-06-15 18:21:48 -0700546
547 // If master type is a special type that needs extra values to be written to
548 // stream, we write those values.
549 if (master_type_.name() == kStructValueType) {
550 // We got a StartList with google.protobuf.Value master type. This means
551 // we have to start the "list_value" within google.protobuf.Value.
Feng Xiaoe841bac2015-12-11 17:09:20 -0800552 //
553 // See
554 // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
555 //
556 // Render
557 // "<name>": {
558 // "list_value": {
559 // "values": [ // Start this list.
560 ProtoWriter::StartObject(name);
561 current_.reset(new Item(this, Item::MESSAGE, false, false));
562 Push("list_value", Item::MESSAGE, true, false);
563 Push("values", Item::MESSAGE, true, true);
564 return this;
565 }
566
567 if (master_type_.name() == kStructListValueType) {
Feng Xiaoe96ff302015-06-15 18:21:48 -0700568 // We got a StartList with google.protobuf.ListValue master type. This
569 // means we have to start the "values" within google.protobuf.ListValue.
Feng Xiaoe841bac2015-12-11 17:09:20 -0800570 //
571 // Render
572 // "<name>": {
573 // "values": [ // Start this list.
574 ProtoWriter::StartObject(name);
575 current_.reset(new Item(this, Item::MESSAGE, false, false));
576 Push("values", Item::MESSAGE, true, true);
577 return this;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700578 }
579
Feng Xiaoe841bac2015-12-11 17:09:20 -0800580 // Send the event to ProtoWriter so proper errors can be reported.
581 //
582 // Render a regular list:
583 // "<name>": [
584 ProtoWriter::StartList(name);
585 current_.reset(new Item(this, Item::MESSAGE, false, true));
Feng Xiaoe96ff302015-06-15 18:21:48 -0700586 return this;
587 }
588
Feng Xiaoe841bac2015-12-11 17:09:20 -0800589 if (current_->IsAny()) {
590 current_->any()->StartList(name);
Feng Xiaoe96ff302015-06-15 18:21:48 -0700591 return this;
592 }
Feng Xiaoe96ff302015-06-15 18:21:48 -0700593
Feng Xiaoe841bac2015-12-11 17:09:20 -0800594 // If the top of stack is a map, we are starting a list value within a map.
595 // Since map does not allow repeated values, this can only happen when the map
596 // value is of a special type that renders a list in JSON. These can be one
597 // of 3 cases:
598 // i. We are rendering a list value within google.protobuf.Struct
599 // ii. We are rendering a list value within google.protobuf.Value
600 // iii. We are rendering a list value with type google.protobuf.ListValue.
601 if (current_->IsMap()) {
Jisi Liu46e8ff62015-10-05 11:59:43 -0700602 if (!ValidMapKey(name)) {
Feng Xiaoe841bac2015-12-11 17:09:20 -0800603 IncrementInvalidDepth();
Jisi Liu46e8ff62015-10-05 11:59:43 -0700604 return this;
605 }
606
Feng Xiaoe841bac2015-12-11 17:09:20 -0800607 // Start the repeated map entry object.
608 // Render
609 // { "key": "<name>", "value": {
610 Push("", Item::MESSAGE, false, false);
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700611 ProtoWriter::RenderDataPiece("key",
612 DataPiece(name, use_strict_base64_decoding()));
Feng Xiaoe841bac2015-12-11 17:09:20 -0800613 Push("value", Item::MESSAGE, true, false);
Feng Xiaoe96ff302015-06-15 18:21:48 -0700614
Feng Xiaoe841bac2015-12-11 17:09:20 -0800615 // Make sure we are valid after pushing all above items.
616 if (invalid_depth() > 0) return this;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700617
Feng Xiaoe841bac2015-12-11 17:09:20 -0800618 // case i and ii above. Start "list_value" field within g.p.Value
619 if (element() != NULL && element()->parent_field() != NULL) {
620 // Render
621 // "list_value": {
622 // "values": [ // Start this list
623 if (IsStructValue(*element()->parent_field())) {
624 Push("list_value", Item::MESSAGE, true, false);
625 Push("values", Item::MESSAGE, true, true);
626 return this;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700627 }
Feng Xiaoe96ff302015-06-15 18:21:48 -0700628
Feng Xiaoe841bac2015-12-11 17:09:20 -0800629 // Render
630 // "values": [
631 if (IsStructListValue(*element()->parent_field())) {
632 // case iii above. Bind directly to g.p.ListValue
633 Push("values", Item::MESSAGE, true, true);
634 return this;
635 }
636 }
637
638 // Report an error.
639 InvalidValue("Map", StrCat("Cannot have repeated items ('", name,
640 "') within a map."));
Feng Xiaoe96ff302015-06-15 18:21:48 -0700641 return this;
642 }
643
Feng Xiaoe841bac2015-12-11 17:09:20 -0800644 // When name is empty and stack is not empty, we are rendering an item within
645 // a list.
646 if (name.empty()) {
647 if (element() != NULL && element()->parent_field() != NULL) {
648 if (IsStructValue(*element()->parent_field())) {
649 // Since it is g.p.Value, we bind directly to the list_value.
650 // Render
651 // { // g.p.Value item within the list
652 // "list_value": {
653 // "values": [
654 Push("", Item::MESSAGE, false, false);
655 Push("list_value", Item::MESSAGE, true, false);
656 Push("values", Item::MESSAGE, true, true);
657 return this;
658 }
659
660 if (IsStructListValue(*element()->parent_field())) {
661 // Since it is g.p.ListValue, we bind to it directly.
662 // Render
663 // { // g.p.ListValue item within the list
664 // "values": [
665 Push("", Item::MESSAGE, false, false);
666 Push("values", Item::MESSAGE, true, true);
667 return this;
668 }
669 }
670
671 // Pass the event to underlying ProtoWriter.
672 Push(name, Item::MESSAGE, false, true);
673 return this;
674 }
675
676 // name is not empty
677 const google::protobuf::Field* field = Lookup(name);
678 if (field == NULL) {
679 IncrementInvalidDepth();
680 return this;
681 }
682
683 if (IsStructValue(*field)) {
684 // If g.p.Value is repeated, start that list. Otherwise, start the
685 // "list_value" within it.
686 if (IsRepeated(*field)) {
687 // Render it just like a regular repeated field.
688 // "<name>": [
689 Push(name, Item::MESSAGE, false, true);
690 return this;
691 }
692
693 // Start the "list_value" field.
694 // Render
695 // "<name>": {
696 // "list_value": {
697 // "values": [
698 Push(name, Item::MESSAGE, false, false);
699 Push("list_value", Item::MESSAGE, true, false);
700 Push("values", Item::MESSAGE, true, true);
701 return this;
702 }
703
704 if (IsStructListValue(*field)) {
705 // If g.p.ListValue is repeated, start that list. Otherwise, start the
706 // "values" within it.
707 if (IsRepeated(*field)) {
708 // Render it just like a regular repeated field.
709 // "<name>": [
710 Push(name, Item::MESSAGE, false, true);
711 return this;
712 }
713
714 // Start the "values" field within g.p.ListValue.
715 // Render
716 // "<name>": {
717 // "values": [
718 Push(name, Item::MESSAGE, false, false);
719 Push("values", Item::MESSAGE, true, true);
720 return this;
721 }
722
723 // If we are here, the field should be repeated. Report an error otherwise.
724 if (!IsRepeated(*field)) {
725 IncrementInvalidDepth();
726 InvalidName(name, "Proto field is not repeating, cannot start list.");
727 return this;
728 }
729
730 if (IsMap(*field)) {
731 InvalidValue("Map",
732 StrCat("Cannot bind a list to map for field '", name, "'."));
733 IncrementInvalidDepth();
734 return this;
735 }
736
737 // Pass the event to ProtoWriter.
738 // Render
739 // "<name>": [
740 Push(name, Item::MESSAGE, false, true);
Feng Xiaoe96ff302015-06-15 18:21:48 -0700741 return this;
742}
743
744ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndList() {
Feng Xiaoe841bac2015-12-11 17:09:20 -0800745 if (invalid_depth() > 0) {
746 DecrementInvalidDepth();
747 return this;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700748 }
749
Feng Xiaoe841bac2015-12-11 17:09:20 -0800750 if (current_ == NULL) return this;
751
752 if (current_->IsAny()) {
753 current_->any()->EndList();
754 return this;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700755 }
Feng Xiaoe841bac2015-12-11 17:09:20 -0800756
757 Pop();
Feng Xiaoe96ff302015-06-15 18:21:48 -0700758 return this;
759}
760
761Status ProtoStreamObjectWriter::RenderStructValue(ProtoStreamObjectWriter* ow,
762 const DataPiece& data) {
763 string struct_field_name;
764 switch (data.type()) {
765 // Our JSON parser parses numbers as either int64, uint64, or double.
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700766 case DataPiece::TYPE_INT64: {
767 // If the option to treat integers as strings is set, then render them as
768 // strings. Otherwise, fallback to rendering them as double.
769 if (ow->options_.struct_integers_as_strings) {
770 StatusOr<int64> int_value = data.ToInt64();
771 if (int_value.ok()) {
772 ow->ProtoWriter::RenderDataPiece(
773 "string_value",
774 DataPiece(SimpleItoa(int_value.ValueOrDie()), true));
775 return Status::OK;
776 }
777 }
778 struct_field_name = "number_value";
779 break;
780 }
781 case DataPiece::TYPE_UINT64: {
782 // If the option to treat integers as strings is set, then render them as
783 // strings. Otherwise, fallback to rendering them as double.
784 if (ow->options_.struct_integers_as_strings) {
785 StatusOr<uint64> int_value = data.ToUint64();
786 if (int_value.ok()) {
787 ow->ProtoWriter::RenderDataPiece(
788 "string_value",
789 DataPiece(SimpleItoa(int_value.ValueOrDie()), true));
790 return Status::OK;
791 }
792 }
793 struct_field_name = "number_value";
794 break;
795 }
Feng Xiaoe96ff302015-06-15 18:21:48 -0700796 case DataPiece::TYPE_DOUBLE: {
797 struct_field_name = "number_value";
798 break;
799 }
800 case DataPiece::TYPE_STRING: {
801 struct_field_name = "string_value";
802 break;
803 }
804 case DataPiece::TYPE_BOOL: {
805 struct_field_name = "bool_value";
806 break;
807 }
808 case DataPiece::TYPE_NULL: {
809 struct_field_name = "null_value";
810 break;
811 }
812 default: {
813 return Status(INVALID_ARGUMENT,
814 "Invalid struct data type. Only number, string, boolean or "
815 "null values are supported.");
816 }
817 }
Feng Xiaoe841bac2015-12-11 17:09:20 -0800818 ow->ProtoWriter::RenderDataPiece(struct_field_name, data);
Feng Xiaoe96ff302015-06-15 18:21:48 -0700819 return Status::OK;
820}
821
822Status ProtoStreamObjectWriter::RenderTimestamp(ProtoStreamObjectWriter* ow,
823 const DataPiece& data) {
824 if (data.type() != DataPiece::TYPE_STRING) {
825 return Status(INVALID_ARGUMENT,
826 StrCat("Invalid data type for timestamp, value is ",
827 data.ValueAsStringOrDefault("")));
828 }
829
830 StringPiece value(data.str());
831
832 int64 seconds;
833 int32 nanos;
834 if (!::google::protobuf::internal::ParseTime(value.ToString(), &seconds,
835 &nanos)) {
836 return Status(INVALID_ARGUMENT, StrCat("Invalid time format: ", value));
837 }
838
839
Feng Xiaoe841bac2015-12-11 17:09:20 -0800840 ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
841 ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos));
Feng Xiaoe96ff302015-06-15 18:21:48 -0700842 return Status::OK;
843}
844
845static inline util::Status RenderOneFieldPath(ProtoStreamObjectWriter* ow,
846 StringPiece path) {
Feng Xiaoe841bac2015-12-11 17:09:20 -0800847 ow->ProtoWriter::RenderDataPiece(
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700848 "paths", DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase), true));
Feng Xiaoe96ff302015-06-15 18:21:48 -0700849 return Status::OK;
850}
851
852Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow,
853 const DataPiece& data) {
854 if (data.type() != DataPiece::TYPE_STRING) {
855 return Status(INVALID_ARGUMENT,
856 StrCat("Invalid data type for field mask, value is ",
857 data.ValueAsStringOrDefault("")));
858 }
859
Feng Xiaoeee38b02015-08-22 18:25:48 -0700860// TODO(tsun): figure out how to do proto descriptor based snake case
861// conversions as much as possible. Because ToSnakeCase sometimes returns the
862// wrong value.
Feng Xiaoe96ff302015-06-15 18:21:48 -0700863 google::protobuf::scoped_ptr<ResultCallback1<util::Status, StringPiece> > callback(
Bo Yang7c14dc82015-09-15 18:25:02 -0700864 google::protobuf::internal::NewPermanentCallback(&RenderOneFieldPath, ow));
Feng Xiaoe96ff302015-06-15 18:21:48 -0700865 return DecodeCompactFieldMaskPaths(data.str(), callback.get());
866}
867
868Status ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow,
869 const DataPiece& data) {
870 if (data.type() != DataPiece::TYPE_STRING) {
871 return Status(INVALID_ARGUMENT,
872 StrCat("Invalid data type for duration, value is ",
873 data.ValueAsStringOrDefault("")));
874 }
875
876 StringPiece value(data.str());
877
878 if (!value.ends_with("s")) {
879 return Status(INVALID_ARGUMENT,
880 "Illegal duration format; duration must end with 's'");
881 }
882 value = value.substr(0, value.size() - 1);
883 int sign = 1;
884 if (value.starts_with("-")) {
885 sign = -1;
886 value = value.substr(1);
887 }
888
889 StringPiece s_secs, s_nanos;
890 SplitSecondsAndNanos(value, &s_secs, &s_nanos);
891 uint64 unsigned_seconds;
892 if (!safe_strtou64(s_secs, &unsigned_seconds)) {
893 return Status(INVALID_ARGUMENT,
894 "Invalid duration format, failed to parse seconds");
895 }
896
Feng Xiaoe841bac2015-12-11 17:09:20 -0800897 int32 nanos = 0;
898 Status nanos_status = GetNanosFromStringPiece(
899 s_nanos, "Invalid duration format, failed to parse nano seconds",
900 "Duration value exceeds limits", &nanos);
901 if (!nanos_status.ok()) {
902 return nanos_status;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700903 }
Feng Xiaoe841bac2015-12-11 17:09:20 -0800904 nanos = sign * nanos;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700905
Feng Xiaoe96ff302015-06-15 18:21:48 -0700906 int64 seconds = sign * unsigned_seconds;
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700907 if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds ||
Feng Xiaoe96ff302015-06-15 18:21:48 -0700908 nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
909 return Status(INVALID_ARGUMENT, "Duration value exceeds limits");
910 }
911
Feng Xiaoe841bac2015-12-11 17:09:20 -0800912 ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
913 ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos));
Feng Xiaoe96ff302015-06-15 18:21:48 -0700914 return Status::OK;
915}
916
917Status ProtoStreamObjectWriter::RenderWrapperType(ProtoStreamObjectWriter* ow,
918 const DataPiece& data) {
Feng Xiaoe841bac2015-12-11 17:09:20 -0800919 ow->ProtoWriter::RenderDataPiece("value", data);
Feng Xiaoe96ff302015-06-15 18:21:48 -0700920 return Status::OK;
921}
922
923ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece(
924 StringPiece name, const DataPiece& data) {
925 Status status;
Feng Xiaoe841bac2015-12-11 17:09:20 -0800926 if (invalid_depth() > 0) return this;
927
928 if (current_ == NULL) {
929 const TypeRenderer* type_renderer =
930 FindTypeRenderer(GetFullTypeWithUrl(master_type_.name()));
931 if (type_renderer == NULL) {
932 InvalidName(name, "Root element must be a message.");
933 return this;
934 }
935 // Render the special type.
936 // "<name>": {
937 // ... Render special type ...
938 // }
939 ProtoWriter::StartObject(name);
940 status = (*type_renderer)(this, data);
941 if (!status.ok()) {
942 InvalidValue(master_type_.name(),
943 StrCat("Field '", name, "', ", status.error_message()));
944 }
945 ProtoWriter::EndObject();
946 return this;
947 }
948
949 if (current_->IsAny()) {
950 current_->any()->RenderDataPiece(name, data);
Feng Xiaoe96ff302015-06-15 18:21:48 -0700951 return this;
952 }
953
954 const google::protobuf::Field* field = NULL;
Feng Xiaoe841bac2015-12-11 17:09:20 -0800955 if (current_->IsMap()) {
956 if (!ValidMapKey(name)) return this;
957
958 // Render an item in repeated map list.
959 // { "key": "<name>", "value":
960 Push("", Item::MESSAGE, false, false);
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700961 ProtoWriter::RenderDataPiece("key",
962 DataPiece(name, use_strict_base64_decoding()));
Feng Xiaoe841bac2015-12-11 17:09:20 -0800963 field = Lookup("value");
Feng Xiaoe96ff302015-06-15 18:21:48 -0700964 if (field == NULL) {
Feng Xiaoe841bac2015-12-11 17:09:20 -0800965 GOOGLE_LOG(DFATAL) << "Map does not have a value field.";
Feng Xiaoe96ff302015-06-15 18:21:48 -0700966 return this;
967 }
Feng Xiaoeee38b02015-08-22 18:25:48 -0700968
Feng Xiaoe841bac2015-12-11 17:09:20 -0800969 const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url());
970 if (type_renderer != NULL) {
971 // Map's value type is a special type. Render it like a message:
972 // "value": {
973 // ... Render special type ...
974 // }
975 Push("value", Item::MESSAGE, true, false);
976 status = (*type_renderer)(this, data);
977 if (!status.ok()) {
978 InvalidValue(field->type_url(),
979 StrCat("Field '", name, "', ", status.error_message()));
980 }
981 Pop();
982 return this;
983 }
Feng Xiaoeee38b02015-08-22 18:25:48 -0700984
Feng Xiaoe841bac2015-12-11 17:09:20 -0800985 // If we are rendering explicit null values and the backend proto field is
986 // not of the google.protobuf.NullType type, we do nothing.
987 if (data.type() == DataPiece::TYPE_NULL &&
988 field->type_url() != kStructNullValueTypeUrl) {
989 return this;
990 }
991
992 // Render the map value as a primitive type.
993 ProtoWriter::RenderDataPiece("value", data);
994 Pop();
995 return this;
Feng Xiaoe96ff302015-06-15 18:21:48 -0700996 }
997
Feng Xiaoe841bac2015-12-11 17:09:20 -0800998 field = Lookup(name);
999 if (field == NULL) return this;
1000
1001 // Check if the field is of special type. Render it accordingly if so.
1002 const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url());
Feng Xiaoe96ff302015-06-15 18:21:48 -07001003 if (type_renderer != NULL) {
Feng Xiaoe841bac2015-12-11 17:09:20 -08001004 Push(name, Item::MESSAGE, false, false);
Feng Xiaoe96ff302015-06-15 18:21:48 -07001005 status = (*type_renderer)(this, data);
1006 if (!status.ok()) {
Feng Xiaoe841bac2015-12-11 17:09:20 -08001007 InvalidValue(field->type_url(),
Feng Xiaoe96ff302015-06-15 18:21:48 -07001008 StrCat("Field '", name, "', ", status.error_message()));
1009 }
Feng Xiaoe841bac2015-12-11 17:09:20 -08001010 Pop();
Feng Xiaoe96ff302015-06-15 18:21:48 -07001011 return this;
1012 }
1013
Feng Xiaoe841bac2015-12-11 17:09:20 -08001014 // If we are rendering explicit null values and the backend proto field is
1015 // not of the google.protobuf.NullType type, we do nothing.
Feng Xiaoe96ff302015-06-15 18:21:48 -07001016 if (data.type() == DataPiece::TYPE_NULL &&
Feng Xiaoe841bac2015-12-11 17:09:20 -08001017 field->type_url() != kStructNullValueTypeUrl) {
1018 return this;
Feng Xiaoe96ff302015-06-15 18:21:48 -07001019 }
1020
Feng Xiaoe841bac2015-12-11 17:09:20 -08001021 ProtoWriter::RenderDataPiece(name, data);
1022 return this;
Feng Xiaoe96ff302015-06-15 18:21:48 -07001023}
1024
1025// Map of functions that are responsible for rendering well known type
1026// represented by the key.
1027hash_map<string, ProtoStreamObjectWriter::TypeRenderer>*
Jisi Liu09778152015-08-25 22:01:12 -07001028 ProtoStreamObjectWriter::renderers_ = NULL;
1029GOOGLE_PROTOBUF_DECLARE_ONCE(writer_renderers_init_);
1030
1031void ProtoStreamObjectWriter::InitRendererMap() {
1032 renderers_ = new hash_map<string, ProtoStreamObjectWriter::TypeRenderer>();
1033 (*renderers_)["type.googleapis.com/google.protobuf.Timestamp"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001034 &ProtoStreamObjectWriter::RenderTimestamp;
Jisi Liu09778152015-08-25 22:01:12 -07001035 (*renderers_)["type.googleapis.com/google.protobuf.Duration"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001036 &ProtoStreamObjectWriter::RenderDuration;
Jisi Liu09778152015-08-25 22:01:12 -07001037 (*renderers_)["type.googleapis.com/google.protobuf.FieldMask"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001038 &ProtoStreamObjectWriter::RenderFieldMask;
Jisi Liu09778152015-08-25 22:01:12 -07001039 (*renderers_)["type.googleapis.com/google.protobuf.Double"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001040 &ProtoStreamObjectWriter::RenderWrapperType;
Jisi Liu09778152015-08-25 22:01:12 -07001041 (*renderers_)["type.googleapis.com/google.protobuf.Float"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001042 &ProtoStreamObjectWriter::RenderWrapperType;
Jisi Liu09778152015-08-25 22:01:12 -07001043 (*renderers_)["type.googleapis.com/google.protobuf.Int64"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001044 &ProtoStreamObjectWriter::RenderWrapperType;
Jisi Liu09778152015-08-25 22:01:12 -07001045 (*renderers_)["type.googleapis.com/google.protobuf.UInt64"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001046 &ProtoStreamObjectWriter::RenderWrapperType;
Jisi Liu09778152015-08-25 22:01:12 -07001047 (*renderers_)["type.googleapis.com/google.protobuf.Int32"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001048 &ProtoStreamObjectWriter::RenderWrapperType;
Jisi Liu09778152015-08-25 22:01:12 -07001049 (*renderers_)["type.googleapis.com/google.protobuf.UInt32"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001050 &ProtoStreamObjectWriter::RenderWrapperType;
Jisi Liu09778152015-08-25 22:01:12 -07001051 (*renderers_)["type.googleapis.com/google.protobuf.Bool"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001052 &ProtoStreamObjectWriter::RenderWrapperType;
Jisi Liu09778152015-08-25 22:01:12 -07001053 (*renderers_)["type.googleapis.com/google.protobuf.String"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001054 &ProtoStreamObjectWriter::RenderWrapperType;
Jisi Liu09778152015-08-25 22:01:12 -07001055 (*renderers_)["type.googleapis.com/google.protobuf.Bytes"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001056 &ProtoStreamObjectWriter::RenderWrapperType;
Jisi Liu09778152015-08-25 22:01:12 -07001057 (*renderers_)["type.googleapis.com/google.protobuf.DoubleValue"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001058 &ProtoStreamObjectWriter::RenderWrapperType;
Jisi Liu09778152015-08-25 22:01:12 -07001059 (*renderers_)["type.googleapis.com/google.protobuf.FloatValue"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001060 &ProtoStreamObjectWriter::RenderWrapperType;
Jisi Liu09778152015-08-25 22:01:12 -07001061 (*renderers_)["type.googleapis.com/google.protobuf.Int64Value"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001062 &ProtoStreamObjectWriter::RenderWrapperType;
Jisi Liu09778152015-08-25 22:01:12 -07001063 (*renderers_)["type.googleapis.com/google.protobuf.UInt64Value"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001064 &ProtoStreamObjectWriter::RenderWrapperType;
Jisi Liu09778152015-08-25 22:01:12 -07001065 (*renderers_)["type.googleapis.com/google.protobuf.Int32Value"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001066 &ProtoStreamObjectWriter::RenderWrapperType;
Jisi Liu09778152015-08-25 22:01:12 -07001067 (*renderers_)["type.googleapis.com/google.protobuf.UInt32Value"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001068 &ProtoStreamObjectWriter::RenderWrapperType;
Jisi Liu09778152015-08-25 22:01:12 -07001069 (*renderers_)["type.googleapis.com/google.protobuf.BoolValue"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001070 &ProtoStreamObjectWriter::RenderWrapperType;
Jisi Liu09778152015-08-25 22:01:12 -07001071 (*renderers_)["type.googleapis.com/google.protobuf.StringValue"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001072 &ProtoStreamObjectWriter::RenderWrapperType;
Jisi Liu09778152015-08-25 22:01:12 -07001073 (*renderers_)["type.googleapis.com/google.protobuf.BytesValue"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001074 &ProtoStreamObjectWriter::RenderWrapperType;
Jisi Liu09778152015-08-25 22:01:12 -07001075 (*renderers_)["type.googleapis.com/google.protobuf.Value"] =
Feng Xiaoe96ff302015-06-15 18:21:48 -07001076 &ProtoStreamObjectWriter::RenderStructValue;
Jisi Liu09778152015-08-25 22:01:12 -07001077 ::google::protobuf::internal::OnShutdown(&DeleteRendererMap);
1078}
1079
1080void ProtoStreamObjectWriter::DeleteRendererMap() {
1081 delete ProtoStreamObjectWriter::renderers_;
1082 renderers_ = NULL;
Feng Xiaoe96ff302015-06-15 18:21:48 -07001083}
1084
1085ProtoStreamObjectWriter::TypeRenderer*
1086ProtoStreamObjectWriter::FindTypeRenderer(const string& type_url) {
Jisi Liu09778152015-08-25 22:01:12 -07001087 ::google::protobuf::GoogleOnceInit(&writer_renderers_init_, &InitRendererMap);
1088 return FindOrNull(*renderers_, type_url);
Feng Xiaoe96ff302015-06-15 18:21:48 -07001089}
1090
Jisi Liu46e8ff62015-10-05 11:59:43 -07001091bool ProtoStreamObjectWriter::ValidMapKey(StringPiece unnormalized_name) {
Feng Xiaoe841bac2015-12-11 17:09:20 -08001092 if (current_ == NULL) return true;
Jisi Liu46e8ff62015-10-05 11:59:43 -07001093
Feng Xiaoe841bac2015-12-11 17:09:20 -08001094 if (!current_->InsertMapKeyIfNotPresent(unnormalized_name)) {
1095 listener()->InvalidName(
1096 location(), unnormalized_name,
Jisi Liu46e8ff62015-10-05 11:59:43 -07001097 StrCat("Repeated map key: '", unnormalized_name, "' is already set."));
1098 return false;
1099 }
1100
1101 return true;
1102}
1103
Feng Xiaoe841bac2015-12-11 17:09:20 -08001104void ProtoStreamObjectWriter::Push(StringPiece name, Item::ItemType item_type,
1105 bool is_placeholder, bool is_list) {
1106 is_list ? ProtoWriter::StartList(name) : ProtoWriter::StartObject(name);
1107
1108 // invalid_depth == 0 means it is a successful StartObject or StartList.
1109 if (invalid_depth() == 0)
1110 current_.reset(
1111 new Item(current_.release(), item_type, is_placeholder, is_list));
Feng Xiaoe96ff302015-06-15 18:21:48 -07001112}
1113
Feng Xiaoe841bac2015-12-11 17:09:20 -08001114void ProtoStreamObjectWriter::Pop() {
1115 // Pop all placeholder items sending StartObject or StartList events to
1116 // ProtoWriter according to is_list value.
1117 while (current_ != NULL && current_->is_placeholder()) {
1118 PopOneElement();
Feng Xiaoe96ff302015-06-15 18:21:48 -07001119 }
Feng Xiaoe841bac2015-12-11 17:09:20 -08001120 if (current_ != NULL) {
1121 PopOneElement();
Feng Xiaoe96ff302015-06-15 18:21:48 -07001122 }
Feng Xiaoe96ff302015-06-15 18:21:48 -07001123}
1124
Feng Xiaoe841bac2015-12-11 17:09:20 -08001125void ProtoStreamObjectWriter::PopOneElement() {
1126 current_->is_list() ? ProtoWriter::EndList() : ProtoWriter::EndObject();
1127 current_.reset(current_->pop<Item>());
Feng Xiaoe96ff302015-06-15 18:21:48 -07001128}
1129
1130bool ProtoStreamObjectWriter::IsMap(const google::protobuf::Field& field) {
1131 if (field.type_url().empty() ||
1132 field.kind() != google::protobuf::Field_Kind_TYPE_MESSAGE ||
1133 field.cardinality() !=
1134 google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
1135 return false;
1136 }
1137 const google::protobuf::Type* field_type =
Feng Xiaoe841bac2015-12-11 17:09:20 -08001138 typeinfo()->GetTypeByTypeUrl(field.type_url());
Feng Xiaoe96ff302015-06-15 18:21:48 -07001139
Feng Xiaobd111982015-08-11 15:07:12 -07001140 // TODO(xiaofeng): Unify option names.
Feng Xiaoe96ff302015-06-15 18:21:48 -07001141 return GetBoolOptionOrDefault(field_type->options(),
Feng Xiaobd111982015-08-11 15:07:12 -07001142 "google.protobuf.MessageOptions.map_entry", false) ||
1143 GetBoolOptionOrDefault(field_type->options(), "map_entry", false);
Feng Xiaoe96ff302015-06-15 18:21:48 -07001144}
1145
Feng Xiaoe841bac2015-12-11 17:09:20 -08001146bool ProtoStreamObjectWriter::IsAny(const google::protobuf::Field& field) {
1147 return GetTypeWithoutUrl(field.type_url()) == kAnyType;
Feng Xiaoe96ff302015-06-15 18:21:48 -07001148}
1149
Feng Xiaoe841bac2015-12-11 17:09:20 -08001150bool ProtoStreamObjectWriter::IsStruct(const google::protobuf::Field& field) {
1151 return GetTypeWithoutUrl(field.type_url()) == kStructType;
1152}
1153
1154bool ProtoStreamObjectWriter::IsStructValue(
1155 const google::protobuf::Field& field) {
1156 return GetTypeWithoutUrl(field.type_url()) == kStructValueType;
1157}
1158
1159bool ProtoStreamObjectWriter::IsStructListValue(
1160 const google::protobuf::Field& field) {
1161 return GetTypeWithoutUrl(field.type_url()) == kStructListValueType;
1162}
Jisi Liu46e8ff62015-10-05 11:59:43 -07001163
Feng Xiaoe96ff302015-06-15 18:21:48 -07001164} // namespace converter
1165} // namespace util
1166} // namespace protobuf
1167} // namespace google