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