• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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[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