1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 #include "google/protobuf/json/internal/unparser.h"
9
10 #include <cfloat>
11 #include <cmath>
12 #include <complex>
13 #include <cstdint>
14 #include <cstring>
15 #include <limits>
16 #include <memory>
17 #include <sstream>
18 #include <string>
19 #include <type_traits>
20 #include <utility>
21
22 #include "absl/log/absl_check.h"
23 #include "absl/log/absl_log.h"
24 #include "absl/status/status.h"
25 #include "absl/strings/ascii.h"
26 #include "absl/strings/escaping.h"
27 #include "absl/strings/str_cat.h"
28 #include "absl/strings/str_format.h"
29 #include "absl/strings/string_view.h"
30 #include "absl/types/optional.h"
31 #include "google/protobuf/descriptor.h"
32 #include "google/protobuf/dynamic_message.h"
33 #include "google/protobuf/io/coded_stream.h"
34 #include "google/protobuf/io/zero_copy_stream.h"
35 #include "google/protobuf/json/internal/descriptor_traits.h"
36 #include "google/protobuf/json/internal/unparser_traits.h"
37 #include "google/protobuf/json/internal/writer.h"
38 #include "google/protobuf/message.h"
39 #include "google/protobuf/stubs/status_macros.h"
40
41 // Must be included last.
42 #include "google/protobuf/port_def.inc"
43
44 namespace google {
45 namespace protobuf {
46 namespace json_internal {
47 namespace {
48 template <typename Traits>
IsEmpty(const Msg<Traits> & msg,const Desc<Traits> & desc)49 bool IsEmpty(const Msg<Traits>& msg, const Desc<Traits>& desc) {
50 size_t count = Traits::FieldCount(desc);
51 for (size_t i = 0; i < count; ++i) {
52 if (Traits::GetSize(Traits::FieldByIndex(desc, i), msg) > 0) {
53 return false;
54 }
55 }
56 return true;
57 }
58
59 enum class IntegerEnumStyle {
60 kQuoted,
61 kUnquoted,
62 };
63
64 template <typename Traits>
WriteEnum(JsonWriter & writer,Field<Traits> field,int32_t value,IntegerEnumStyle int_style=IntegerEnumStyle::kUnquoted)65 void WriteEnum(JsonWriter& writer, Field<Traits> field, int32_t value,
66 IntegerEnumStyle int_style = IntegerEnumStyle::kUnquoted) {
67 if (ClassifyMessage(Traits::FieldTypeName(field)) == MessageType::kNull) {
68 writer.Write("null");
69 return;
70 }
71
72 if (!writer.options().always_print_enums_as_ints) {
73 auto name = Traits::EnumNameByNumber(field, value);
74 if (name.ok()) {
75 writer.Write("\"", *name, "\"");
76 return;
77 }
78 }
79
80 if (int_style == IntegerEnumStyle::kQuoted) {
81 writer.Write("\"", value, "\"");
82 } else {
83 writer.Write(value);
84 }
85 }
86
87 // Returns true if x round-trips through being cast to a double, i.e., if
88 // x is represenable exactly as a double. This is a slightly weaker condition
89 // than x < 2^52.
90 template <typename Int>
RoundTripsThroughDouble(Int x)91 bool RoundTripsThroughDouble(Int x) {
92 auto d = static_cast<double>(x);
93 // d has guaranteed to be finite with no fractional part, because it came from
94 // an integer, so we only need to check that it is not outside of the
95 // representable range of `int`. The way to do this is somewhat not obvious:
96 // UINT64_MAX isn't representable, and what it gets rounded to when we go
97 // int->double is unspecified!
98 //
99 // Thus, we have to go through ldexp.
100 double min = 0;
101 double max_plus_one = std::ldexp(1.0, sizeof(Int) * 8);
102 if (std::is_signed<Int>::value) {
103 max_plus_one /= 2;
104 min = -max_plus_one;
105 }
106
107 if (d < min || d >= max_plus_one) {
108 return false;
109 }
110
111 return static_cast<Int>(d) == x;
112 }
113
114 // Mutually recursive with functions that follow.
115 template <typename Traits>
116 absl::Status WriteMessage(JsonWriter& writer, const Msg<Traits>& msg,
117 const Desc<Traits>& desc, bool is_top_level = false);
118
119 // This is templatized so that defaults, singular, and repeated fields can both
120 // use the same enormous switch-case.
121 template <typename Traits, typename... Args>
WriteSingular(JsonWriter & writer,Field<Traits> field,Args &&...args)122 absl::Status WriteSingular(JsonWriter& writer, Field<Traits> field,
123 Args&&... args) {
124 // When the pack `args` is empty, the caller has requested printing the
125 // default value.
126 bool is_default = sizeof...(Args) == 0;
127 switch (Traits::FieldType(field)) {
128 case FieldDescriptor::TYPE_FLOAT: {
129 auto x = Traits::GetFloat(field, std::forward<Args>(args)...);
130 RETURN_IF_ERROR(x.status());
131 if (writer.options().allow_legacy_syntax && is_default &&
132 !std::isfinite(*x)) {
133 *x = 0;
134 }
135 writer.Write(*x);
136 break;
137 }
138 case FieldDescriptor::TYPE_DOUBLE: {
139 auto x = Traits::GetDouble(field, std::forward<Args>(args)...);
140 RETURN_IF_ERROR(x.status());
141 if (writer.options().allow_legacy_syntax && is_default &&
142 !std::isfinite(*x)) {
143 *x = 0;
144 }
145 writer.Write(*x);
146 break;
147 }
148 case FieldDescriptor::TYPE_SFIXED64:
149 case FieldDescriptor::TYPE_SINT64:
150 case FieldDescriptor::TYPE_INT64: {
151 auto x = Traits::GetInt64(field, std::forward<Args>(args)...);
152 RETURN_IF_ERROR(x.status());
153 if (writer.options().unquote_int64_if_possible &&
154 RoundTripsThroughDouble(*x)) {
155 writer.Write(*x);
156 } else {
157 writer.Write(MakeQuoted(*x));
158 }
159 break;
160 }
161 case FieldDescriptor::TYPE_FIXED64:
162 case FieldDescriptor::TYPE_UINT64: {
163 auto x = Traits::GetUInt64(field, std::forward<Args>(args)...);
164 RETURN_IF_ERROR(x.status());
165 if (writer.options().unquote_int64_if_possible &&
166 RoundTripsThroughDouble(*x)) {
167 writer.Write(*x);
168 } else {
169 writer.Write(MakeQuoted(*x));
170 }
171 break;
172 }
173 case FieldDescriptor::TYPE_SFIXED32:
174 case FieldDescriptor::TYPE_SINT32:
175 case FieldDescriptor::TYPE_INT32: {
176 auto x = Traits::GetInt32(field, std::forward<Args>(args)...);
177 RETURN_IF_ERROR(x.status());
178 writer.Write(*x);
179 break;
180 }
181 case FieldDescriptor::TYPE_FIXED32:
182 case FieldDescriptor::TYPE_UINT32: {
183 auto x = Traits::GetUInt32(field, std::forward<Args>(args)...);
184 RETURN_IF_ERROR(x.status());
185 writer.Write(*x);
186 break;
187 }
188 case FieldDescriptor::TYPE_BOOL: {
189 auto x = Traits::GetBool(field, std::forward<Args>(args)...);
190 RETURN_IF_ERROR(x.status());
191 writer.Write(*x ? "true" : "false");
192 break;
193 }
194 case FieldDescriptor::TYPE_STRING: {
195 auto x = Traits::GetString(field, writer.ScratchBuf(),
196 std::forward<Args>(args)...);
197 RETURN_IF_ERROR(x.status());
198 writer.Write(MakeQuoted(*x));
199 break;
200 }
201 case FieldDescriptor::TYPE_BYTES: {
202 auto x = Traits::GetString(field, writer.ScratchBuf(),
203 std::forward<Args>(args)...);
204 RETURN_IF_ERROR(x.status());
205 if (writer.options().allow_legacy_syntax && is_default) {
206 // Although difficult to verify, it appears that the original ESF parser
207 // fails to unescape the contents of a
208 // google.protobuf.Field.default_value, which may potentially be
209 // escaped if it is for a `bytes` field (note that default_value is a
210 // `string` regardless of what type the field is).
211 //
212 // However, our parser's type.proto guts actually know to do this
213 // correctly, so this bug must be manually re-introduced.
214 writer.WriteBase64(absl::CEscape(*x));
215 } else {
216 writer.WriteBase64(*x);
217 }
218 break;
219 }
220 case FieldDescriptor::TYPE_ENUM: {
221 auto x = Traits::GetEnumValue(field, std::forward<Args>(args)...);
222 RETURN_IF_ERROR(x.status());
223 WriteEnum<Traits>(writer, field, *x);
224 break;
225 }
226 case FieldDescriptor::TYPE_MESSAGE:
227 case FieldDescriptor::TYPE_GROUP: {
228 auto x = Traits::GetMessage(field, std::forward<Args>(args)...);
229 RETURN_IF_ERROR(x.status());
230 return WriteMessage<Traits>(writer, **x, Traits::GetDesc(**x));
231 }
232 default:
233 return absl::InvalidArgumentError(
234 absl::StrCat("unsupported field type: ", Traits::FieldType(field)));
235 }
236
237 return absl::OkStatus();
238 }
239
240 template <typename Traits>
WriteRepeated(JsonWriter & writer,const Msg<Traits> & msg,Field<Traits> field)241 absl::Status WriteRepeated(JsonWriter& writer, const Msg<Traits>& msg,
242 Field<Traits> field) {
243 writer.Write("[");
244 writer.Push();
245
246 size_t count = Traits::GetSize(field, msg);
247 bool first = true;
248 for (size_t i = 0; i < count; ++i) {
249 if (ClassifyMessage(Traits::FieldTypeName(field)) == MessageType::kValue) {
250 bool empty = false;
251 RETURN_IF_ERROR(Traits::WithFieldType(
252 field, [&](const Desc<Traits>& desc) -> absl::Status {
253 auto inner = Traits::GetMessage(field, msg, i);
254 RETURN_IF_ERROR(inner.status());
255 empty = IsEmpty<Traits>(**inner, desc);
256 return absl::OkStatus();
257 }));
258
259 // Empty google.protobuf.Values are silently discarded.
260 if (empty) {
261 continue;
262 }
263 }
264 writer.WriteComma(first);
265 writer.NewLine();
266 RETURN_IF_ERROR(WriteSingular<Traits>(writer, field, msg, i));
267 }
268
269 writer.Pop();
270 if (!first) {
271 writer.NewLine();
272 }
273 writer.Write("]");
274 return absl::OkStatus();
275 }
276
277 template <typename Traits>
WriteMapKey(JsonWriter & writer,const Msg<Traits> & entry,Field<Traits> field)278 absl::Status WriteMapKey(JsonWriter& writer, const Msg<Traits>& entry,
279 Field<Traits> field) {
280 switch (Traits::FieldType(field)) {
281 case FieldDescriptor::TYPE_SFIXED64:
282 case FieldDescriptor::TYPE_SINT64:
283 case FieldDescriptor::TYPE_INT64: {
284 auto x = Traits::GetInt64(field, entry);
285 RETURN_IF_ERROR(x.status());
286 writer.Write(MakeQuoted(*x));
287 break;
288 }
289 case FieldDescriptor::TYPE_FIXED64:
290 case FieldDescriptor::TYPE_UINT64: {
291 auto x = Traits::GetUInt64(field, entry);
292 RETURN_IF_ERROR(x.status());
293 writer.Write(MakeQuoted(*x));
294 break;
295 }
296 case FieldDescriptor::TYPE_SFIXED32:
297 case FieldDescriptor::TYPE_SINT32:
298 case FieldDescriptor::TYPE_INT32: {
299 auto x = Traits::GetInt32(field, entry);
300 RETURN_IF_ERROR(x.status());
301 writer.Write(MakeQuoted(*x));
302 break;
303 }
304 case FieldDescriptor::TYPE_FIXED32:
305 case FieldDescriptor::TYPE_UINT32: {
306 auto x = Traits::GetUInt32(field, entry);
307 RETURN_IF_ERROR(x.status());
308 writer.Write(MakeQuoted(*x));
309 break;
310 }
311 case FieldDescriptor::TYPE_BOOL: {
312 auto x = Traits::GetBool(field, entry);
313 RETURN_IF_ERROR(x.status());
314 writer.Write(MakeQuoted(*x ? "true" : "false"));
315 break;
316 }
317 case FieldDescriptor::TYPE_STRING: {
318 auto x = Traits::GetString(field, writer.ScratchBuf(), entry);
319 RETURN_IF_ERROR(x.status());
320 writer.Write(MakeQuoted(*x));
321 break;
322 }
323 case FieldDescriptor::TYPE_ENUM: {
324 auto x = Traits::GetEnumValue(field, entry);
325 RETURN_IF_ERROR(x.status());
326 WriteEnum<Traits>(writer, field, *x, IntegerEnumStyle::kQuoted);
327 break;
328 }
329 default:
330 return absl::InvalidArgumentError(
331 absl::StrCat("unsupported map key type: ", Traits::FieldType(field)));
332 }
333 return absl::OkStatus();
334 }
335
336 template <typename Traits>
IsEmptyValue(const Msg<Traits> & msg,Field<Traits> field)337 absl::StatusOr<bool> IsEmptyValue(const Msg<Traits>& msg, Field<Traits> field) {
338 if (ClassifyMessage(Traits::FieldTypeName(field)) != MessageType::kValue) {
339 return false;
340 }
341 bool empty = false;
342 RETURN_IF_ERROR(Traits::WithFieldType(
343 field, [&](const Desc<Traits>& desc) -> absl::Status {
344 auto inner = Traits::GetMessage(field, msg);
345 RETURN_IF_ERROR(inner.status());
346 empty = IsEmpty<Traits>(**inner, desc);
347 return absl::OkStatus();
348 }));
349 return empty;
350 }
351
352 template <typename Traits>
WriteMap(JsonWriter & writer,const Msg<Traits> & msg,Field<Traits> field)353 absl::Status WriteMap(JsonWriter& writer, const Msg<Traits>& msg,
354 Field<Traits> field) {
355 writer.Write("{");
356 writer.Push();
357
358 size_t count = Traits::GetSize(field, msg);
359 bool first = true;
360 for (size_t i = 0; i < count; ++i) {
361 absl::StatusOr<const Msg<Traits>*> entry =
362 Traits::GetMessage(field, msg, i);
363 RETURN_IF_ERROR(entry.status());
364 const Desc<Traits>& type = Traits::GetDesc(**entry);
365
366 auto is_empty = IsEmptyValue<Traits>(**entry, Traits::ValueField(type));
367 RETURN_IF_ERROR(is_empty.status());
368 if (*is_empty) {
369 // Empty google.protobuf.Values are silently discarded.
370 continue;
371 }
372
373 writer.WriteComma(first);
374 writer.NewLine();
375 RETURN_IF_ERROR(
376 WriteMapKey<Traits>(writer, **entry, Traits::KeyField(type)));
377 writer.Write(":");
378 writer.Whitespace(" ");
379 RETURN_IF_ERROR(
380 WriteSingular<Traits>(writer, Traits::ValueField(type), **entry));
381 }
382
383 writer.Pop();
384 if (!first) {
385 writer.NewLine();
386 }
387 writer.Write("}");
388 return absl::OkStatus();
389 }
390
391 template <typename Traits>
WriteField(JsonWriter & writer,const Msg<Traits> & msg,Field<Traits> field,bool & first)392 absl::Status WriteField(JsonWriter& writer, const Msg<Traits>& msg,
393 Field<Traits> field, bool& first) {
394 if (!Traits::IsRepeated(field)) { // Repeated case is handled in
395 // WriteRepeated.
396 auto is_empty = IsEmptyValue<Traits>(msg, field);
397 RETURN_IF_ERROR(is_empty.status());
398 if (*is_empty) {
399 // Empty google.protobuf.Values are silently discarded.
400 return absl::OkStatus();
401 }
402 }
403
404 writer.WriteComma(first);
405 writer.NewLine();
406
407 if (Traits::IsExtension(field)) {
408 writer.Write(MakeQuoted("[", Traits::FieldFullName(field), "]"), ":");
409 } else if (writer.options().preserve_proto_field_names) {
410 writer.Write(MakeQuoted(Traits::FieldName(field)), ":");
411 } else {
412 // The generator for type.proto and the internals of descriptor.cc disagree
413 // on what the json name of a PascalCase field is supposed to be; type.proto
414 // seems to (incorrectly?) capitalize the first letter, which is the
415 // behavior ESF defaults to. To fix this, if the original field name starts
416 // with an uppercase letter, and the Json name does not, we uppercase it.
417 absl::string_view original_name = Traits::FieldName(field);
418 absl::string_view json_name = Traits::FieldJsonName(field);
419 if (writer.options().allow_legacy_syntax &&
420 absl::ascii_isupper(original_name[0]) &&
421 !absl::ascii_isupper(json_name[0])) {
422 writer.Write(MakeQuoted(absl::ascii_toupper(original_name[0]),
423 original_name.substr(1)),
424 ":");
425 } else {
426 writer.Write(MakeQuoted(json_name), ":");
427 }
428 }
429 writer.Whitespace(" ");
430
431 if (Traits::IsMap(field)) {
432 return WriteMap<Traits>(writer, msg, field);
433 } else if (Traits::IsRepeated(field)) {
434 return WriteRepeated<Traits>(writer, msg, field);
435 } else if (Traits::GetSize(field, msg) == 0) {
436
437 if (Traits::FieldType(field) == FieldDescriptor::TYPE_GROUP) {
438 // We do not yet have full group support, but this is required so that we
439 // pass the same tests as the ESF parser.
440 writer.Write("null");
441 return absl::OkStatus();
442 }
443 return WriteSingular<Traits>(writer, field);
444 }
445
446 return WriteSingular<Traits>(writer, field, msg);
447 }
448
449 template <typename Traits>
WriteFields(JsonWriter & writer,const Msg<Traits> & msg,const Desc<Traits> & desc,bool & first)450 absl::Status WriteFields(JsonWriter& writer, const Msg<Traits>& msg,
451 const Desc<Traits>& desc, bool& first) {
452 std::vector<Field<Traits>> fields;
453 size_t total = Traits::FieldCount(desc);
454 fields.reserve(total);
455 for (size_t i = 0; i < total; ++i) {
456 Field<Traits> field = Traits::FieldByIndex(desc, i);
457
458 bool has = Traits::GetSize(field, msg) > 0;
459
460 if (writer.options().always_print_fields_with_no_presence) {
461 has |= Traits::IsRepeated(field) || Traits::IsImplicitPresence(field);
462 }
463
464 if (has) {
465 fields.push_back(field);
466 }
467 }
468
469 // Add extensions *before* sorting.
470 Traits::FindAndAppendExtensions(msg, fields);
471
472 // Fields are guaranteed to be serialized in field number order.
473 absl::c_sort(fields, [](const auto& a, const auto& b) {
474 return Traits::FieldNumber(a) < Traits::FieldNumber(b);
475 });
476
477 for (auto field : fields) {
478 RETURN_IF_ERROR(WriteField<Traits>(writer, msg, field, first));
479 }
480
481 return absl::OkStatus();
482 }
483
484 template <typename Traits>
485 absl::Status WriteStructValue(JsonWriter& writer, const Msg<Traits>& msg,
486 const Desc<Traits>& desc);
487 template <typename Traits>
488 absl::Status WriteListValue(JsonWriter& writer, const Msg<Traits>& msg,
489 const Desc<Traits>& desc);
490
491 template <typename Traits>
WriteValue(JsonWriter & writer,const Msg<Traits> & msg,const Desc<Traits> & desc,bool is_top_level)492 absl::Status WriteValue(JsonWriter& writer, const Msg<Traits>& msg,
493 const Desc<Traits>& desc, bool is_top_level) {
494 // NOTE: The field numbers 1 through 6 are the numbers of the oneof fields in
495 // google.protobuf.Value. Conformance tests verify the correctness of these
496 // numbers.
497 if (Traits::GetSize(Traits::MustHaveField(desc, 1), msg) > 0) {
498 writer.Write("null");
499 return absl::OkStatus();
500 }
501
502 auto number_field = Traits::MustHaveField(desc, 2);
503 if (Traits::GetSize(number_field, msg) > 0) {
504 auto x = Traits::GetDouble(number_field, msg);
505 RETURN_IF_ERROR(x.status());
506 if (std::isnan(*x)) {
507 return absl::InvalidArgumentError(
508 "google.protobuf.Value cannot encode double values for nan, "
509 "because it would be parsed as a string");
510 }
511 if (*x == std::numeric_limits<double>::infinity() ||
512 *x == -std::numeric_limits<double>::infinity()) {
513 return absl::InvalidArgumentError(
514 "google.protobuf.Value cannot encode double values for "
515 "infinity, because it would be parsed as a string");
516 }
517 writer.Write(*x);
518 return absl::OkStatus();
519 }
520
521 auto string_field = Traits::MustHaveField(desc, 3);
522 if (Traits::GetSize(string_field, msg) > 0) {
523 auto x = Traits::GetString(string_field, writer.ScratchBuf(), msg);
524 RETURN_IF_ERROR(x.status());
525 writer.Write(MakeQuoted(*x));
526 return absl::OkStatus();
527 }
528
529 auto bool_field = Traits::MustHaveField(desc, 4);
530 if (Traits::GetSize(bool_field, msg) > 0) {
531 auto x = Traits::GetBool(bool_field, msg);
532 RETURN_IF_ERROR(x.status());
533 writer.Write(*x ? "true" : "false");
534 return absl::OkStatus();
535 }
536
537 auto struct_field = Traits::MustHaveField(desc, 5);
538 if (Traits::GetSize(struct_field, msg) > 0) {
539 auto x = Traits::GetMessage(struct_field, msg);
540 RETURN_IF_ERROR(x.status());
541 return Traits::WithFieldType(struct_field, [&](const Desc<Traits>& type) {
542 return WriteStructValue<Traits>(writer, **x, type);
543 });
544 }
545
546 auto list_field = Traits::MustHaveField(desc, 6);
547 if (Traits::GetSize(list_field, msg) > 0) {
548 auto x = Traits::GetMessage(list_field, msg);
549 RETURN_IF_ERROR(x.status());
550 return Traits::WithFieldType(list_field, [&](const Desc<Traits>& type) {
551 return WriteListValue<Traits>(writer, **x, type);
552 });
553 }
554
555 ABSL_CHECK(is_top_level)
556 << "empty, non-top-level Value must be handled one layer "
557 "up, since it prints an empty string; reaching this "
558 "statement is always a bug";
559 return absl::OkStatus();
560 }
561
562 template <typename Traits>
WriteStructValue(JsonWriter & writer,const Msg<Traits> & msg,const Desc<Traits> & desc)563 absl::Status WriteStructValue(JsonWriter& writer, const Msg<Traits>& msg,
564 const Desc<Traits>& desc) {
565 return WriteMap<Traits>(writer, msg, Traits::MustHaveField(desc, 1));
566 }
567
568 template <typename Traits>
WriteListValue(JsonWriter & writer,const Msg<Traits> & msg,const Desc<Traits> & desc)569 absl::Status WriteListValue(JsonWriter& writer, const Msg<Traits>& msg,
570 const Desc<Traits>& desc) {
571 return WriteRepeated<Traits>(writer, msg, Traits::MustHaveField(desc, 1));
572 }
573
574 template <typename Traits>
WriteTimestamp(JsonWriter & writer,const Msg<Traits> & msg,const Desc<Traits> & desc)575 absl::Status WriteTimestamp(JsonWriter& writer, const Msg<Traits>& msg,
576 const Desc<Traits>& desc) {
577 auto secs_field = Traits::MustHaveField(desc, 1);
578 auto secs = Traits::GetSize(secs_field, msg) > 0
579 ? Traits::GetInt64(secs_field, msg)
580 : 0;
581 RETURN_IF_ERROR(secs.status());
582
583 if (*secs < -62135596800) {
584 return absl::InvalidArgumentError(
585 "minimum acceptable time value is 0001-01-01T00:00:00Z");
586 } else if (*secs > 253402300799) {
587 return absl::InvalidArgumentError(
588 "maximum acceptable time value is 9999-12-31T23:59:59Z");
589 }
590
591 // Ensure seconds is positive.
592 *secs += 62135596800;
593
594 auto nanos_field = Traits::MustHaveField(desc, 2);
595 auto nanos = Traits::GetSize(nanos_field, msg) > 0
596 ? Traits::GetInt32(nanos_field, msg)
597 : 0;
598 RETURN_IF_ERROR(nanos.status());
599
600 // Julian Day -> Y/M/D, Algorithm from:
601 // Fliegel, H. F., and Van Flandern, T. C., "A Machine Algorithm for
602 // Processing Calendar Dates," Communications of the Association of
603 // Computing Machines, vol. 11 (1968), p. 657.
604 int32_t L, N, I, J, K;
605 L = static_cast<int32_t>(*secs / 86400) - 719162 + 68569 + 2440588;
606 N = 4 * L / 146097;
607 L = L - (146097 * N + 3) / 4;
608 I = 4000 * (L + 1) / 1461001;
609 L = L - 1461 * I / 4 + 31;
610 J = 80 * L / 2447;
611 K = L - 2447 * J / 80;
612 L = J / 11;
613 J = J + 2 - 12 * L;
614 I = 100 * (N - 49) + I + L;
615
616 int32_t sec = *secs % 60;
617 int32_t min = (*secs / 60) % 60;
618 int32_t hour = (*secs / 3600) % 24;
619
620 if (*nanos == 0) {
621 writer.Write(absl::StrFormat(R"("%04d-%02d-%02dT%02d:%02d:%02dZ")", I, J, K,
622 hour, min, sec));
623 return absl::OkStatus();
624 }
625
626 size_t digits = 9;
627 uint32_t frac_seconds = std::abs(*nanos);
628 while (frac_seconds % 1000 == 0) {
629 frac_seconds /= 1000;
630 digits -= 3;
631 }
632
633 writer.Write(absl::StrFormat(R"("%04d-%02d-%02dT%02d:%02d:%02d.%.*dZ")", I, J,
634 K, hour, min, sec, digits, frac_seconds));
635 return absl::OkStatus();
636 }
637
638 template <typename Traits>
WriteDuration(JsonWriter & writer,const Msg<Traits> & msg,const Desc<Traits> & desc)639 absl::Status WriteDuration(JsonWriter& writer, const Msg<Traits>& msg,
640 const Desc<Traits>& desc) {
641 constexpr int64_t kMaxSeconds = int64_t{3652500} * 86400;
642 constexpr int64_t kMaxNanos = 999999999;
643
644 auto secs_field = Traits::MustHaveField(desc, 1);
645 auto secs = Traits::GetSize(secs_field, msg) > 0
646 ? Traits::GetInt64(secs_field, msg)
647 : 0;
648 RETURN_IF_ERROR(secs.status());
649
650 if (*secs > kMaxSeconds || *secs < -kMaxSeconds) {
651 return absl::InvalidArgumentError("duration out of range");
652 }
653
654 auto nanos_field = Traits::MustHaveField(desc, 2);
655 auto nanos = Traits::GetSize(nanos_field, msg) > 0
656 ? Traits::GetInt32(nanos_field, msg)
657 : 0;
658 RETURN_IF_ERROR(nanos.status());
659
660 if (*nanos > kMaxNanos || *nanos < -kMaxNanos) {
661 return absl::InvalidArgumentError("duration out of range");
662 }
663 if ((*secs != 0) && (*nanos != 0) && ((*secs < 0) != (*nanos < 0))) {
664 return absl::InvalidArgumentError("nanos and seconds signs do not match");
665 }
666
667 if (*nanos == 0) {
668 writer.Write(absl::StrFormat(R"("%ds")", *secs));
669 return absl::OkStatus();
670 }
671
672 size_t digits = 9;
673 uint32_t frac_seconds = std::abs(*nanos);
674 while (frac_seconds % 1000 == 0) {
675 frac_seconds /= 1000;
676 digits -= 3;
677 }
678
679 absl::string_view sign = ((*secs < 0) || (*nanos < 0)) ? "-" : "";
680 writer.Write(absl::StrFormat(R"("%s%d.%.*ds")", sign, std::abs(*secs), digits,
681 frac_seconds));
682 return absl::OkStatus();
683 }
684
685 template <typename Traits>
WriteFieldMask(JsonWriter & writer,const Msg<Traits> & msg,const Desc<Traits> & desc)686 absl::Status WriteFieldMask(JsonWriter& writer, const Msg<Traits>& msg,
687 const Desc<Traits>& desc) {
688 // google.protobuf.FieldMask has a single field with number 1.
689 auto paths_field = Traits::MustHaveField(desc, 1);
690 size_t paths = Traits::GetSize(paths_field, msg);
691 writer.Write('"');
692
693 bool first = true;
694 for (size_t i = 0; i < paths; ++i) {
695 writer.WriteComma(first);
696 auto path = Traits::GetString(paths_field, writer.ScratchBuf(), msg, i);
697 RETURN_IF_ERROR(path.status());
698 bool saw_under = false;
699 for (char c : *path) {
700 if (absl::ascii_islower(c) && saw_under) {
701 writer.Write(absl::ascii_toupper(c));
702 } else if (absl::ascii_isdigit(c) || absl::ascii_islower(c) || c == '.') {
703 writer.Write(c);
704 } else if (c == '_' &&
705 (!saw_under || writer.options().allow_legacy_syntax)) {
706 saw_under = true;
707 continue;
708 } else if (!writer.options().allow_legacy_syntax) {
709 return absl::InvalidArgumentError("unexpected character in FieldMask");
710 } else {
711 if (saw_under) {
712 writer.Write('_');
713 }
714 writer.Write(c);
715 }
716 saw_under = false;
717 }
718 }
719 writer.Write('"');
720
721 return absl::OkStatus();
722 }
723
724 template <typename Traits>
WriteAny(JsonWriter & writer,const Msg<Traits> & msg,const Desc<Traits> & desc)725 absl::Status WriteAny(JsonWriter& writer, const Msg<Traits>& msg,
726 const Desc<Traits>& desc) {
727 auto type_url_field = Traits::MustHaveField(desc, 1);
728 auto value_field = Traits::MustHaveField(desc, 2);
729
730 bool has_type_url = Traits::GetSize(type_url_field, msg) > 0;
731 bool has_value = Traits::GetSize(value_field, msg) > 0;
732 if (!has_type_url && !has_value) {
733 writer.Write("{}");
734 return absl::OkStatus();
735 } else if (!has_type_url) {
736 return absl::InvalidArgumentError("broken Any: missing type URL");
737 } else if (!has_value && !writer.options().allow_legacy_syntax) {
738 return absl::InvalidArgumentError("broken Any: missing value");
739 }
740
741 writer.Write("{");
742 writer.Push();
743
744 auto type_url = Traits::GetString(type_url_field, writer.ScratchBuf(), msg);
745 RETURN_IF_ERROR(type_url.status());
746 writer.NewLine();
747 writer.Write("\"@type\":");
748 writer.Whitespace(" ");
749 writer.Write(MakeQuoted(*type_url));
750
751 return Traits::WithDynamicType(
752 desc, std::string(*type_url),
753 [&](const Desc<Traits>& any_desc) -> absl::Status {
754 absl::string_view any_bytes;
755 if (has_value) {
756 absl::StatusOr<absl::string_view> bytes =
757 Traits::GetString(value_field, writer.ScratchBuf(), msg);
758 RETURN_IF_ERROR(bytes.status());
759 any_bytes = *bytes;
760 }
761
762 return Traits::WithDecodedMessage(
763 any_desc, any_bytes,
764 [&](const Msg<Traits>& unerased) -> absl::Status {
765 bool first = false;
766 if (ClassifyMessage(Traits::TypeName(any_desc)) !=
767 MessageType::kNotWellKnown) {
768 writer.WriteComma(first);
769 writer.NewLine();
770 writer.Write("\"value\":");
771 writer.Whitespace(" ");
772 RETURN_IF_ERROR(
773 WriteMessage<Traits>(writer, unerased, any_desc));
774 } else {
775 RETURN_IF_ERROR(
776 WriteFields<Traits>(writer, unerased, any_desc, first));
777 }
778 writer.Pop();
779 if (!first) {
780 writer.NewLine();
781 }
782 writer.Write("}");
783 return absl::OkStatus();
784 });
785 });
786 }
787
788 template <typename Traits>
WriteMessage(JsonWriter & writer,const Msg<Traits> & msg,const Desc<Traits> & desc,bool is_top_level)789 absl::Status WriteMessage(JsonWriter& writer, const Msg<Traits>& msg,
790 const Desc<Traits>& desc, bool is_top_level) {
791 switch (ClassifyMessage(Traits::TypeName(desc))) {
792 case MessageType::kAny:
793 return WriteAny<Traits>(writer, msg, desc);
794 case MessageType::kWrapper: {
795 auto field = Traits::MustHaveField(desc, 1);
796 if (Traits::GetSize(field, msg) == 0) {
797 return WriteSingular<Traits>(writer, field);
798 }
799 return WriteSingular<Traits>(writer, field, msg);
800 }
801 case MessageType::kValue:
802 return WriteValue<Traits>(writer, msg, desc, is_top_level);
803 case MessageType::kStruct:
804 return WriteStructValue<Traits>(writer, msg, desc);
805 case MessageType::kList:
806 return WriteListValue<Traits>(writer, msg, desc);
807 case MessageType::kTimestamp:
808 return WriteTimestamp<Traits>(writer, msg, desc);
809 case MessageType::kDuration:
810 return WriteDuration<Traits>(writer, msg, desc);
811 case MessageType::kFieldMask:
812 return WriteFieldMask<Traits>(writer, msg, desc);
813 default: {
814 writer.Write("{");
815 writer.Push();
816 bool first = true;
817 RETURN_IF_ERROR(WriteFields<Traits>(writer, msg, desc, first));
818 writer.Pop();
819 if (!first) {
820 writer.NewLine();
821 }
822 writer.Write("}");
823 return absl::OkStatus();
824 }
825 }
826 }
827 } // namespace
828
MessageToJsonString(const Message & message,std::string * output,json_internal::WriterOptions options)829 absl::Status MessageToJsonString(const Message& message, std::string* output,
830 json_internal::WriterOptions options) {
831 if (PROTOBUF_DEBUG) {
832 ABSL_DLOG(INFO) << "json2/input: " << message.DebugString();
833 }
834 io::StringOutputStream out(output);
835 JsonWriter writer(&out, options);
836 absl::Status s = WriteMessage<UnparseProto2Descriptor>(
837 writer, message, *message.GetDescriptor(), /*is_top_level=*/true);
838 if (PROTOBUF_DEBUG) ABSL_DLOG(INFO) << "json2/status: " << s;
839 RETURN_IF_ERROR(s);
840
841 writer.NewLine();
842 if (PROTOBUF_DEBUG) {
843 ABSL_DLOG(INFO) << "json2/output: " << absl::CHexEscape(*output);
844 }
845 return absl::OkStatus();
846 }
847
BinaryToJsonStream(google::protobuf::util::TypeResolver * resolver,const std::string & type_url,io::ZeroCopyInputStream * binary_input,io::ZeroCopyOutputStream * json_output,json_internal::WriterOptions options)848 absl::Status BinaryToJsonStream(google::protobuf::util::TypeResolver* resolver,
849 const std::string& type_url,
850 io::ZeroCopyInputStream* binary_input,
851 io::ZeroCopyOutputStream* json_output,
852 json_internal::WriterOptions options) {
853 // NOTE: Most of the contortions in this function are to allow for capture of
854 // input and output of the parser in ABSL_DLOG mode. Destruction order is very
855 // critical in this function, because io::ZeroCopy*Stream types usually only
856 // flush on destruction.
857
858 // For ABSL_DLOG, we would like to print out the input and output, which
859 // requires buffering both instead of doing "zero copy". This block, and the
860 // one at the end of the function, set up and tear down interception of the
861 // input and output streams.
862 std::string copy;
863 std::string out;
864 absl::optional<io::ArrayInputStream> tee_input;
865 absl::optional<io::StringOutputStream> tee_output;
866 if (PROTOBUF_DEBUG) {
867 const void* data;
868 int len;
869 while (binary_input->Next(&data, &len)) {
870 copy.resize(copy.size() + len);
871 std::memcpy(©[copy.size() - len], data, len);
872 }
873 tee_input.emplace(copy.data(), copy.size());
874 tee_output.emplace(&out);
875 ABSL_DLOG(INFO) << "json2/input: " << absl::BytesToHexString(copy);
876 }
877
878 ResolverPool pool(resolver);
879 auto desc = pool.FindMessage(type_url);
880 RETURN_IF_ERROR(desc.status());
881
882 io::CodedInputStream stream(tee_input.has_value() ? &*tee_input
883 : binary_input);
884 auto msg = UntypedMessage::ParseFromStream(*desc, stream);
885 RETURN_IF_ERROR(msg.status());
886
887 JsonWriter writer(tee_output.has_value() ? &*tee_output : json_output,
888 options);
889 absl::Status s = WriteMessage<UnparseProto3Type>(
890 writer, *msg, UnparseProto3Type::GetDesc(*msg),
891 /*is_top_level=*/true);
892 if (PROTOBUF_DEBUG) ABSL_DLOG(INFO) << "json2/status: " << s;
893 RETURN_IF_ERROR(s);
894
895 if (PROTOBUF_DEBUG) {
896 tee_output.reset(); // Flush the output stream.
897 io::zc_sink_internal::ZeroCopyStreamByteSink(json_output)
898 .Append(out.data(), out.size());
899 ABSL_DLOG(INFO) << "json2/output: " << absl::CHexEscape(out);
900 }
901
902 writer.NewLine();
903 return absl::OkStatus();
904 }
905 } // namespace json_internal
906 } // namespace protobuf
907 } // namespace google
908