/proc/self/cwd/external/com_google_protobuf/src/google/protobuf/json/internal/parser.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/parser.h" |
32 | | |
33 | | #include <cfloat> |
34 | | #include <cmath> |
35 | | #include <cstdint> |
36 | | #include <cstring> |
37 | | #include <limits> |
38 | | #include <memory> |
39 | | #include <string> |
40 | | #include <utility> |
41 | | |
42 | | #include "google/protobuf/type.pb.h" |
43 | | #include "google/protobuf/descriptor.h" |
44 | | #include "google/protobuf/dynamic_message.h" |
45 | | #include "google/protobuf/message.h" |
46 | | #include "absl/base/attributes.h" |
47 | | #include "absl/container/flat_hash_set.h" |
48 | | #include "absl/log/absl_check.h" |
49 | | #include "absl/log/absl_log.h" |
50 | | #include "absl/status/status.h" |
51 | | #include "absl/status/statusor.h" |
52 | | #include "absl/strings/ascii.h" |
53 | | #include "absl/strings/escaping.h" |
54 | | #include "absl/strings/match.h" |
55 | | #include "absl/strings/numbers.h" |
56 | | #include "absl/strings/str_format.h" |
57 | | #include "absl/strings/str_split.h" |
58 | | #include "absl/strings/string_view.h" |
59 | | #include "absl/types/optional.h" |
60 | | #include "absl/types/span.h" |
61 | | #include "google/protobuf/io/zero_copy_sink.h" |
62 | | #include "google/protobuf/io/zero_copy_stream.h" |
63 | | #include "google/protobuf/io/zero_copy_stream_impl_lite.h" |
64 | | #include "google/protobuf/json/internal/descriptor_traits.h" |
65 | | #include "google/protobuf/json/internal/lexer.h" |
66 | | #include "google/protobuf/json/internal/parser_traits.h" |
67 | | #include "google/protobuf/util/type_resolver.h" |
68 | | #include "google/protobuf/stubs/status_macros.h" |
69 | | |
70 | | // Must be included last. |
71 | | #include "google/protobuf/port_def.inc" |
72 | | |
73 | | namespace google { |
74 | | namespace protobuf { |
75 | | namespace json_internal { |
76 | | namespace { |
77 | | // This file contains code that drives a JsonLexer to visit a JSON document and |
78 | | // convert it into some form of proto. |
79 | | // |
80 | | // This semantic layer is duplicated: proto2-ish code can deserialize directly |
81 | | // into a message, whereas proto3-ish code deserializes into a byte stream, |
82 | | // using TypeResolvers instead of Descriptors. |
83 | | // |
84 | | // The parsing code is templated over which of these two reflection + output |
85 | | // combinations is used. The traits types that collect the per-instantiation |
86 | | // functionality can be found in json_util2_parser_traits-inl.h. |
87 | | |
88 | | // This table maps an unsigned `char` value, interpreted as an ASCII character, |
89 | | // to a corresponding value in the base64 alphabet (both traditional and |
90 | | // "web-safe" characters are included). |
91 | | // |
92 | | // If a character is not valid base64, it maps to -1; this is used by the bit |
93 | | // operations that assemble a base64-encoded word to determine if an error |
94 | | // occurred, by checking the sign bit. |
95 | | constexpr signed char kBase64Table[256] = { |
96 | | -1, -1, -1, -1, -1, -1, -1, |
97 | | -1, -1, -1, -1, -1, -1, -1, |
98 | | -1, -1, -1, -1, -1, -1, -1, |
99 | | -1, -1, -1, -1, -1, -1, -1, |
100 | | -1, -1, -1, -1, -1, -1, -1, |
101 | | -1, -1, -1, -1, -1, -1, -1, |
102 | | -1, 62 /*+*/, -1, 62 /*-*/, -1, 63 /*/ */, 52 /*0*/, |
103 | | 53 /*1*/, 54 /*2*/, 55 /*3*/, 56 /*4*/, 57 /*5*/, 58 /*6*/, 59 /*7*/, |
104 | | 60 /*8*/, 61 /*9*/, -1, -1, -1, -1, -1, |
105 | | -1, -1, 0 /*A*/, 1 /*B*/, 2 /*C*/, 3 /*D*/, 4 /*E*/, |
106 | | 5 /*F*/, 6 /*G*/, 07 /*H*/, 8 /*I*/, 9 /*J*/, 10 /*K*/, 11 /*L*/, |
107 | | 12 /*M*/, 13 /*N*/, 14 /*O*/, 15 /*P*/, 16 /*Q*/, 17 /*R*/, 18 /*S*/, |
108 | | 19 /*T*/, 20 /*U*/, 21 /*V*/, 22 /*W*/, 23 /*X*/, 24 /*Y*/, 25 /*Z*/, |
109 | | -1, -1, -1, -1, 63 /*_*/, -1, 26 /*a*/, |
110 | | 27 /*b*/, 28 /*c*/, 29 /*d*/, 30 /*e*/, 31 /*f*/, 32 /*g*/, 33 /*h*/, |
111 | | 34 /*i*/, 35 /*j*/, 36 /*k*/, 37 /*l*/, 38 /*m*/, 39 /*n*/, 40 /*o*/, |
112 | | 41 /*p*/, 42 /*q*/, 43 /*r*/, 44 /*s*/, 45 /*t*/, 46 /*u*/, 47 /*v*/, |
113 | | 48 /*w*/, 49 /*x*/, 50 /*y*/, 51 /*z*/, -1, -1, -1, |
114 | | -1, -1, -1, -1, -1, -1, -1, |
115 | | -1, -1, -1, -1, -1, -1, -1, |
116 | | -1, -1, -1, -1, -1, -1, -1, |
117 | | -1, -1, -1, -1, -1, -1, -1, |
118 | | -1, -1, -1, -1, -1, -1, -1, |
119 | | -1, -1, -1, -1, -1, -1, -1, |
120 | | -1, -1, -1, -1, -1, -1, -1, |
121 | | -1, -1, -1, -1, -1, -1, -1, |
122 | | -1, -1, -1, -1, -1, -1, -1, |
123 | | -1, -1, -1, -1, -1, -1, -1, |
124 | | -1, -1, -1, -1, -1, -1, -1, |
125 | | -1, -1, -1, -1, -1, -1, -1, |
126 | | -1, -1, -1, -1, -1, -1, -1, |
127 | | -1, -1, -1, -1, -1, -1, -1, |
128 | | -1, -1, -1, -1, -1, -1, -1, |
129 | | -1, -1, -1, -1, -1, -1, -1, |
130 | | -1, -1, -1, -1, -1, -1, -1, |
131 | | -1, -1, -1, -1, -1, -1, -1, |
132 | | -1, -1, -1, -1}; |
133 | | |
134 | 0 | uint32_t Base64Lookup(char c) { |
135 | | // Sign-extend return value so high bit will be set on any unexpected char. |
136 | 0 | return static_cast<uint32_t>(kBase64Table[static_cast<uint8_t>(c)]); |
137 | 0 | } |
138 | | |
139 | | // Decodes `base64` in-place, shrinking the length as appropriate. |
140 | 0 | absl::StatusOr<absl::Span<char>> DecodeBase64InPlace(absl::Span<char> base64) { |
141 | | // We decode in place. This is safe because this is a new buffer (not |
142 | | // aliasing the input) and because base64 decoding shrinks 4 bytes into 3. |
143 | 0 | char* out = base64.data(); |
144 | 0 | const char* ptr = base64.data(); |
145 | 0 | const char* end = ptr + base64.size(); |
146 | 0 | const char* end4 = ptr + (base64.size() & ~3u); |
147 | |
|
148 | 0 | for (; ptr < end4; ptr += 4, out += 3) { |
149 | 0 | auto val = Base64Lookup(ptr[0]) << 18 | Base64Lookup(ptr[1]) << 12 | |
150 | 0 | Base64Lookup(ptr[2]) << 6 | Base64Lookup(ptr[3]) << 0; |
151 | |
|
152 | 0 | if (static_cast<int32_t>(val) < 0) { |
153 | | // Junk chars or padding. Remove trailing padding, if any. |
154 | 0 | if (end - ptr == 4 && ptr[3] == '=') { |
155 | 0 | if (ptr[2] == '=') { |
156 | 0 | end -= 2; |
157 | 0 | } else { |
158 | 0 | end -= 1; |
159 | 0 | } |
160 | 0 | } |
161 | 0 | break; |
162 | 0 | } |
163 | | |
164 | 0 | out[0] = val >> 16; |
165 | 0 | out[1] = (val >> 8) & 0xff; |
166 | 0 | out[2] = val & 0xff; |
167 | 0 | } |
168 | |
|
169 | 0 | if (ptr < end) { |
170 | 0 | uint32_t val = ~0u; |
171 | 0 | switch (end - ptr) { |
172 | 0 | case 2: |
173 | 0 | val = Base64Lookup(ptr[0]) << 18 | Base64Lookup(ptr[1]) << 12; |
174 | 0 | out[0] = val >> 16; |
175 | 0 | out += 1; |
176 | 0 | break; |
177 | 0 | case 3: |
178 | 0 | val = Base64Lookup(ptr[0]) << 18 | Base64Lookup(ptr[1]) << 12 | |
179 | 0 | Base64Lookup(ptr[2]) << 6; |
180 | 0 | out[0] = val >> 16; |
181 | 0 | out[1] = (val >> 8) & 0xff; |
182 | 0 | out += 2; |
183 | 0 | break; |
184 | 0 | } |
185 | | |
186 | 0 | if (static_cast<int32_t>(val) < 0) { |
187 | 0 | return absl::InvalidArgumentError("corrupt base64"); |
188 | 0 | } |
189 | 0 | } |
190 | | |
191 | 0 | return absl::Span<char>(base64.data(), |
192 | 0 | static_cast<size_t>(out - base64.data())); |
193 | 0 | } |
194 | | |
195 | | template <typename T> |
196 | | absl::StatusOr<LocationWith<T>> ParseIntInner(JsonLexer& lex, double lo, |
197 | 0 | double hi) { |
198 | 0 | absl::StatusOr<JsonLexer::Kind> kind = lex.PeekKind(); |
199 | 0 | RETURN_IF_ERROR(kind.status()); |
200 | | |
201 | 0 | LocationWith<T> n; |
202 | 0 | switch (*kind) { |
203 | 0 | case JsonLexer::kNum: { |
204 | 0 | absl::StatusOr<LocationWith<MaybeOwnedString>> x = lex.ParseRawNumber(); |
205 | 0 | RETURN_IF_ERROR(x.status()); |
206 | 0 | n.loc = x->loc; |
207 | 0 | if (absl::SimpleAtoi(x->value.AsView(), &n.value)) { |
208 | 0 | break; |
209 | 0 | } |
210 | | |
211 | 0 | double d; |
212 | 0 | if (!absl::SimpleAtod(x->value.AsView(), &d) || !std::isfinite(d)) { |
213 | 0 | return x->loc.Invalid( |
214 | 0 | absl::StrFormat("invalid number: '%s'", x->value.AsView())); |
215 | 0 | } |
216 | | |
217 | | // Conversion overflow here would be UB. |
218 | 0 | if (lo > d || d > hi) { |
219 | 0 | return lex.Invalid("JSON number out of range for int"); |
220 | 0 | } |
221 | 0 | n.value = static_cast<T>(d); |
222 | 0 | if (d - static_cast<double>(n.value) != 0) { |
223 | 0 | return lex.Invalid( |
224 | 0 | "expected integer, but JSON number had fractional part"); |
225 | 0 | } |
226 | 0 | break; |
227 | 0 | } |
228 | 0 | case JsonLexer::kStr: { |
229 | 0 | absl::StatusOr<LocationWith<MaybeOwnedString>> str = lex.ParseUtf8(); |
230 | 0 | RETURN_IF_ERROR(str.status()); |
231 | | // SimpleAtoi will ignore leading and trailing whitespace, so we need |
232 | | // to check for it ourselves. |
233 | 0 | for (char c : str->value.AsView()) { |
234 | 0 | if (absl::ascii_isspace(c)) { |
235 | 0 | return lex.Invalid("non-number characters in quoted number"); |
236 | 0 | } |
237 | 0 | } |
238 | 0 | if (!absl::SimpleAtoi(str->value.AsView(), &n.value)) { |
239 | 0 | return str->loc.Invalid("non-number characters in quoted number"); |
240 | 0 | } |
241 | 0 | n.loc = str->loc; |
242 | 0 | break; |
243 | 0 | } |
244 | 0 | default: |
245 | 0 | return lex.Invalid("expected number or string"); |
246 | 0 | } |
247 | | |
248 | 0 | return n; |
249 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::StatusOr<google::protobuf::json_internal::LocationWith<long> > google::protobuf::json_internal::(anonymous namespace)::ParseIntInner<long>(google::protobuf::json_internal::JsonLexer&, double, double) Unexecuted instantiation: parser.cc:absl::lts_20230125::StatusOr<google::protobuf::json_internal::LocationWith<unsigned long> > google::protobuf::json_internal::(anonymous namespace)::ParseIntInner<unsigned long>(google::protobuf::json_internal::JsonLexer&, double, double) |
250 | | |
251 | | template <typename Traits> |
252 | 0 | absl::StatusOr<int64_t> ParseInt(JsonLexer& lex, Field<Traits> field) { |
253 | 0 | absl::StatusOr<LocationWith<int64_t>> n = |
254 | 0 | ParseIntInner<int64_t>(lex, -9007199254740992.0, 9007199254740992.0); |
255 | 0 | RETURN_IF_ERROR(n.status()); |
256 | | |
257 | 0 | if (Traits::Is32Bit(field)) { |
258 | 0 | if (std::numeric_limits<int32_t>::min() > n->value || |
259 | 0 | n->value > std::numeric_limits<int32_t>::max()) { |
260 | 0 | return n->loc.Invalid("integer out of range"); |
261 | 0 | } |
262 | 0 | } |
263 | | |
264 | 0 | return n->value; |
265 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::StatusOr<long> google::protobuf::json_internal::(anonymous namespace)::ParseInt<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Field) Unexecuted instantiation: parser.cc:absl::lts_20230125::StatusOr<long> google::protobuf::json_internal::(anonymous namespace)::ParseInt<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Field) |
266 | | |
267 | | template <typename Traits> |
268 | 0 | absl::StatusOr<uint64_t> ParseUInt(JsonLexer& lex, Field<Traits> field) { |
269 | 0 | absl::StatusOr<LocationWith<uint64_t>> n = |
270 | 0 | ParseIntInner<uint64_t>(lex, 0, 18014398509481984.0); |
271 | 0 | RETURN_IF_ERROR(n.status()); |
272 | | |
273 | 0 | if (Traits::Is32Bit(field)) { |
274 | 0 | if (n->value > std::numeric_limits<uint32_t>::max()) { |
275 | 0 | return n->loc.Invalid("integer out of range"); |
276 | 0 | } |
277 | 0 | } |
278 | | |
279 | 0 | return n->value; |
280 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::StatusOr<unsigned long> google::protobuf::json_internal::(anonymous namespace)::ParseUInt<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Field) Unexecuted instantiation: parser.cc:absl::lts_20230125::StatusOr<unsigned long> google::protobuf::json_internal::(anonymous namespace)::ParseUInt<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Field) |
281 | | |
282 | | template <typename Traits> |
283 | 0 | absl::StatusOr<double> ParseFp(JsonLexer& lex, Field<Traits> field) { |
284 | 0 | absl::StatusOr<JsonLexer::Kind> kind = lex.PeekKind(); |
285 | 0 | RETURN_IF_ERROR(kind.status()); |
286 | | |
287 | 0 | double n; |
288 | 0 | switch (*kind) { |
289 | 0 | case JsonLexer::kNum: { |
290 | 0 | absl::StatusOr<LocationWith<double>> d = lex.ParseNumber(); |
291 | 0 | RETURN_IF_ERROR(d.status()); |
292 | 0 | n = d->value; |
293 | 0 | break; |
294 | 0 | } |
295 | 0 | case JsonLexer::kStr: { |
296 | 0 | absl::StatusOr<LocationWith<MaybeOwnedString>> str = lex.ParseUtf8(); |
297 | 0 | RETURN_IF_ERROR(str.status()); |
298 | | |
299 | 0 | if (str->value == "NaN") { |
300 | 0 | n = NAN; |
301 | 0 | } else if (str->value == "Infinity") { |
302 | 0 | n = INFINITY; |
303 | 0 | } else if (str->value == "-Infinity") { |
304 | 0 | n = -INFINITY; |
305 | 0 | } else if (!absl::SimpleAtod(str->value.AsView(), &n)) { |
306 | 0 | return str->loc.Invalid("non-number characters in quoted number"); |
307 | 0 | } |
308 | 0 | break; |
309 | 0 | } |
310 | 0 | default: |
311 | 0 | return lex.Invalid("expected number or string"); |
312 | 0 | } |
313 | | |
314 | 0 | if (Traits::Is32Bit(field)) { |
315 | | // Detect out-of-range 32-bit floats by seeing whether the conversion result |
316 | | // is still finite. Finite extreme values may have textual representations |
317 | | // that parse to 64-bit values outside the 32-bit range, but which are |
318 | | // closer to the 32-bit extreme than to the "next value with the same |
319 | | // precision". |
320 | 0 | if (std::isfinite(n) && !std::isfinite(static_cast<float>(n))) { |
321 | 0 | return lex.Invalid("float out of range"); |
322 | 0 | } |
323 | 0 | } |
324 | | |
325 | 0 | return n; |
326 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::StatusOr<double> google::protobuf::json_internal::(anonymous namespace)::ParseFp<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Field) Unexecuted instantiation: parser.cc:absl::lts_20230125::StatusOr<double> google::protobuf::json_internal::(anonymous namespace)::ParseFp<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Field) |
327 | | |
328 | | template <typename Traits> |
329 | | absl::StatusOr<std::string> ParseStrOrBytes(JsonLexer& lex, |
330 | 0 | Field<Traits> field) { |
331 | 0 | absl::StatusOr<LocationWith<MaybeOwnedString>> str = lex.ParseUtf8(); |
332 | 0 | RETURN_IF_ERROR(str.status()); |
333 | | |
334 | 0 | if (Traits::FieldType(field) == FieldDescriptor::TYPE_BYTES) { |
335 | 0 | std::string& b64 = str->value.ToString(); |
336 | 0 | absl::StatusOr<absl::Span<char>> decoded = |
337 | 0 | DecodeBase64InPlace(absl::MakeSpan(&b64[0], b64.size())); |
338 | 0 | if (!decoded.ok()) { |
339 | 0 | return str->loc.Invalid(decoded.status().message()); |
340 | 0 | } |
341 | 0 | b64.resize(decoded->size()); |
342 | 0 | } |
343 | | |
344 | 0 | return std::move(str->value.ToString()); |
345 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::StatusOr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > google::protobuf::json_internal::(anonymous namespace)::ParseStrOrBytes<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Field) Unexecuted instantiation: parser.cc:absl::lts_20230125::StatusOr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > google::protobuf::json_internal::(anonymous namespace)::ParseStrOrBytes<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Field) |
346 | | |
347 | | template <typename Traits> |
348 | | absl::StatusOr<absl::optional<int32_t>> ParseEnumFromStr(JsonLexer& lex, |
349 | | MaybeOwnedString& str, |
350 | 0 | Field<Traits> field) { |
351 | 0 | absl::StatusOr<int32_t> value = Traits::EnumNumberByName( |
352 | 0 | field, str.AsView(), lex.options().case_insensitive_enum_parsing); |
353 | 0 | if (value.ok()) { |
354 | 0 | return absl::optional<int32_t>(*value); |
355 | 0 | } |
356 | | |
357 | 0 | int32_t i; |
358 | 0 | if (absl::SimpleAtoi(str.AsView(), &i)) { |
359 | 0 | return absl::optional<int32_t>(i); |
360 | 0 | } else if (lex.options().ignore_unknown_fields) { |
361 | 0 | return {absl::nullopt}; |
362 | 0 | } |
363 | | |
364 | 0 | return value.status(); |
365 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::StatusOr<absl::lts_20230125::optional<int> > google::protobuf::json_internal::(anonymous namespace)::ParseEnumFromStr<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::MaybeOwnedString&, google::protobuf::json_internal::ParseProto2Descriptor::Field) Unexecuted instantiation: parser.cc:absl::lts_20230125::StatusOr<absl::lts_20230125::optional<int> > google::protobuf::json_internal::(anonymous namespace)::ParseEnumFromStr<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::MaybeOwnedString&, google::protobuf::json_internal::ParseProto3Type::Field) |
366 | | |
367 | | // Parses an enum; can return nullopt if a quoted enumerator that we don't |
368 | | // know about is received and `ignore_unknown_fields` is set. |
369 | | template <typename Traits> |
370 | | absl::StatusOr<absl::optional<int32_t>> ParseEnum(JsonLexer& lex, |
371 | 0 | Field<Traits> field) { |
372 | 0 | absl::StatusOr<JsonLexer::Kind> kind = lex.PeekKind(); |
373 | 0 | RETURN_IF_ERROR(kind.status()); |
374 | | |
375 | 0 | int32_t n = 0; |
376 | 0 | switch (*kind) { |
377 | 0 | case JsonLexer::kStr: { |
378 | 0 | absl::StatusOr<LocationWith<MaybeOwnedString>> str = lex.ParseUtf8(); |
379 | 0 | RETURN_IF_ERROR(str.status()); |
380 | | |
381 | 0 | auto e = ParseEnumFromStr<Traits>(lex, str->value, field); |
382 | 0 | RETURN_IF_ERROR(e.status()); |
383 | 0 | if (!e->has_value()) { |
384 | 0 | return {absl::nullopt}; |
385 | 0 | } |
386 | 0 | n = **e; |
387 | 0 | break; |
388 | 0 | } |
389 | 0 | case JsonLexer::kNum: |
390 | 0 | return ParseInt<Traits>(lex, field); |
391 | 0 | default: |
392 | 0 | return lex.Invalid("expected number or string"); |
393 | 0 | } |
394 | | |
395 | 0 | return n; |
396 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::StatusOr<absl::lts_20230125::optional<int> > google::protobuf::json_internal::(anonymous namespace)::ParseEnum<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Field) Unexecuted instantiation: parser.cc:absl::lts_20230125::StatusOr<absl::lts_20230125::optional<int> > google::protobuf::json_internal::(anonymous namespace)::ParseEnum<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Field) |
397 | | |
398 | | // Mutually recursive with functions that follow. |
399 | | template <typename Traits> |
400 | | absl::Status ParseMessage(JsonLexer& lex, const Desc<Traits>& desc, |
401 | | Msg<Traits>& msg, bool any_reparse); |
402 | | template <typename Traits> |
403 | | absl::Status ParseField(JsonLexer& lex, const Desc<Traits>& desc, |
404 | | absl::string_view name, Msg<Traits>& msg); |
405 | | |
406 | | template <typename Traits> |
407 | | absl::Status ParseSingular(JsonLexer& lex, Field<Traits> field, |
408 | 0 | Msg<Traits>& msg) { |
409 | 0 | auto field_type = Traits::FieldType(field); |
410 | 0 | if (lex.Peek(JsonLexer::kNull)) { |
411 | 0 | auto message_type = ClassifyMessage(Traits::FieldTypeName(field)); |
412 | 0 | switch (field_type) { |
413 | 0 | case FieldDescriptor::TYPE_ENUM: |
414 | 0 | if (message_type == MessageType::kNull) { |
415 | 0 | Traits::SetEnum(field, msg, 0); |
416 | 0 | } |
417 | 0 | break; |
418 | 0 | case FieldDescriptor::TYPE_MESSAGE: { |
419 | 0 | if (message_type == MessageType::kValue) { |
420 | 0 | return Traits::NewMsg( |
421 | 0 | field, msg, |
422 | 0 | [&](const Desc<Traits>& type, Msg<Traits>& msg) -> absl::Status { |
423 | 0 | auto field = Traits::FieldByNumber(type, 1); |
424 | 0 | ABSL_DCHECK(field.has_value()); |
425 | 0 | RETURN_IF_ERROR(lex.Expect("null")); |
426 | 0 | Traits::SetEnum(Traits::MustHaveField(type, 1), msg, 0); |
427 | 0 | return absl::OkStatus(); |
428 | 0 | }); Unexecuted instantiation: parser.cc:google::protobuf::json_internal::(anonymous namespace)::ParseSingular<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Field, google::protobuf::json_internal::ParseProto2Descriptor::Msg&)::{lambda(google::protobuf::Descriptor const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&)#1}::operator()(google::protobuf::Descriptor const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&) const Unexecuted instantiation: parser.cc:google::protobuf::json_internal::(anonymous namespace)::ParseSingular<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Field, google::protobuf::json_internal::ParseProto3Type::Msg&)::{lambda(google::protobuf::json_internal::ResolverPool::Message const&, google::protobuf::json_internal::ParseProto3Type::Msg&)#1}::operator()(google::protobuf::json_internal::ResolverPool::Message const&, google::protobuf::json_internal::ParseProto3Type::Msg&) const |
429 | 0 | } |
430 | 0 | break; |
431 | 0 | } |
432 | 0 | default: |
433 | 0 | break; |
434 | 0 | } |
435 | 0 | return lex.Expect("null"); |
436 | 0 | } |
437 | | |
438 | 0 | switch (field_type) { |
439 | 0 | case FieldDescriptor::TYPE_FLOAT: { |
440 | 0 | auto x = ParseFp<Traits>(lex, field); |
441 | 0 | RETURN_IF_ERROR(x.status()); |
442 | 0 | Traits::SetFloat(field, msg, *x); |
443 | 0 | break; |
444 | 0 | } |
445 | 0 | case FieldDescriptor::TYPE_DOUBLE: { |
446 | 0 | auto x = ParseFp<Traits>(lex, field); |
447 | 0 | RETURN_IF_ERROR(x.status()); |
448 | 0 | Traits::SetDouble(field, msg, *x); |
449 | 0 | break; |
450 | 0 | } |
451 | | |
452 | 0 | case FieldDescriptor::TYPE_SFIXED64: |
453 | 0 | case FieldDescriptor::TYPE_SINT64: |
454 | 0 | case FieldDescriptor::TYPE_INT64: { |
455 | 0 | auto x = ParseInt<Traits>(lex, field); |
456 | 0 | RETURN_IF_ERROR(x.status()); |
457 | 0 | Traits::SetInt64(field, msg, *x); |
458 | 0 | break; |
459 | 0 | } |
460 | 0 | case FieldDescriptor::TYPE_FIXED64: |
461 | 0 | case FieldDescriptor::TYPE_UINT64: { |
462 | 0 | auto x = ParseUInt<Traits>(lex, field); |
463 | 0 | RETURN_IF_ERROR(x.status()); |
464 | 0 | Traits::SetUInt64(field, msg, *x); |
465 | 0 | break; |
466 | 0 | } |
467 | | |
468 | 0 | case FieldDescriptor::TYPE_SFIXED32: |
469 | 0 | case FieldDescriptor::TYPE_SINT32: |
470 | 0 | case FieldDescriptor::TYPE_INT32: { |
471 | 0 | auto x = ParseInt<Traits>(lex, field); |
472 | 0 | RETURN_IF_ERROR(x.status()); |
473 | 0 | Traits::SetInt32(field, msg, static_cast<int32_t>(*x)); |
474 | 0 | break; |
475 | 0 | } |
476 | 0 | case FieldDescriptor::TYPE_FIXED32: |
477 | 0 | case FieldDescriptor::TYPE_UINT32: { |
478 | 0 | auto x = ParseUInt<Traits>(lex, field); |
479 | 0 | RETURN_IF_ERROR(x.status()); |
480 | 0 | Traits::SetUInt32(field, msg, static_cast<uint32_t>(*x)); |
481 | 0 | break; |
482 | 0 | } |
483 | 0 | case FieldDescriptor::TYPE_BOOL: { |
484 | 0 | absl::StatusOr<JsonLexer::Kind> kind = lex.PeekKind(); |
485 | 0 | RETURN_IF_ERROR(kind.status()); |
486 | | |
487 | 0 | switch (*kind) { |
488 | 0 | case JsonLexer::kTrue: |
489 | 0 | RETURN_IF_ERROR(lex.Expect("true")); |
490 | 0 | Traits::SetBool(field, msg, true); |
491 | 0 | break; |
492 | 0 | case JsonLexer::kFalse: |
493 | 0 | RETURN_IF_ERROR(lex.Expect("false")); |
494 | 0 | Traits::SetBool(field, msg, false); |
495 | 0 | break; |
496 | 0 | case JsonLexer::kStr: { |
497 | 0 | if (!lex.options().allow_legacy_syntax) { |
498 | 0 | goto bad; |
499 | 0 | } |
500 | | |
501 | 0 | auto x = lex.ParseUtf8(); |
502 | 0 | RETURN_IF_ERROR(x.status()); |
503 | | |
504 | 0 | bool flag; |
505 | 0 | if (!absl::SimpleAtob(x->value, &flag)) { |
506 | | // Is this error a lie? Do we accept things otyher than "true" and |
507 | | // "false" because SimpleAtob does? Absolutely! |
508 | 0 | return x->loc.Invalid("expected 'true' or 'false'"); |
509 | 0 | } |
510 | 0 | Traits::SetBool(field, msg, flag); |
511 | |
|
512 | 0 | break; |
513 | 0 | } |
514 | 0 | bad: |
515 | 0 | default: |
516 | 0 | return lex.Invalid("expected 'true' or 'false'"); |
517 | 0 | } |
518 | 0 | break; |
519 | 0 | } |
520 | 0 | case FieldDescriptor::TYPE_STRING: |
521 | 0 | case FieldDescriptor::TYPE_BYTES: { |
522 | 0 | auto x = ParseStrOrBytes<Traits>(lex, field); |
523 | 0 | RETURN_IF_ERROR(x.status()); |
524 | 0 | Traits::SetString(field, msg, *x); |
525 | 0 | break; |
526 | 0 | } |
527 | 0 | case FieldDescriptor::TYPE_ENUM: { |
528 | 0 | absl::StatusOr<absl::optional<int32_t>> x = ParseEnum<Traits>(lex, field); |
529 | 0 | RETURN_IF_ERROR(x.status()); |
530 | | |
531 | 0 | if (x->has_value() || Traits::IsImplicitPresence(field)) { |
532 | 0 | Traits::SetEnum(field, msg, x->value_or(0)); |
533 | 0 | } |
534 | 0 | break; |
535 | 0 | } |
536 | 0 | case FieldDescriptor::TYPE_MESSAGE: |
537 | 0 | case FieldDescriptor::TYPE_GROUP: { |
538 | 0 | return Traits::NewMsg( |
539 | 0 | field, msg, |
540 | 0 | [&](const Desc<Traits>& type, Msg<Traits>& msg) -> absl::Status { |
541 | 0 | return ParseMessage<Traits>(lex, type, msg, |
542 | 0 | /*any_reparse=*/false); |
543 | 0 | }); Unexecuted instantiation: parser.cc:google::protobuf::json_internal::(anonymous namespace)::ParseSingular<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Field, google::protobuf::json_internal::ParseProto2Descriptor::Msg&)::{lambda(google::protobuf::Descriptor const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&)#2}::operator()(google::protobuf::Descriptor const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&) const Unexecuted instantiation: parser.cc:google::protobuf::json_internal::(anonymous namespace)::ParseSingular<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Field, google::protobuf::json_internal::ParseProto3Type::Msg&)::{lambda(google::protobuf::json_internal::ResolverPool::Message const&, google::protobuf::json_internal::ParseProto3Type::Msg&)#2}::operator()(google::protobuf::json_internal::ResolverPool::Message const&, google::protobuf::json_internal::ParseProto3Type::Msg&) const |
544 | 0 | } |
545 | 0 | default: |
546 | 0 | return lex.Invalid( |
547 | 0 | absl::StrCat("unsupported field type: ", Traits::FieldType(field))); |
548 | 0 | } |
549 | | |
550 | 0 | return absl::OkStatus(); |
551 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseSingular<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Field, google::protobuf::json_internal::ParseProto2Descriptor::Msg&) Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseSingular<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Field, google::protobuf::json_internal::ParseProto3Type::Msg&) |
552 | | |
553 | | template <typename Traits> |
554 | 0 | absl::Status EmitNull(JsonLexer& lex, Field<Traits> field, Msg<Traits>& msg) { |
555 | 0 | switch (Traits::FieldType(field)) { |
556 | 0 | case FieldDescriptor::TYPE_FLOAT: |
557 | 0 | Traits::SetFloat(field, msg, 0); |
558 | 0 | break; |
559 | 0 | case FieldDescriptor::TYPE_DOUBLE: |
560 | 0 | Traits::SetDouble(field, msg, 0); |
561 | 0 | break; |
562 | 0 | case FieldDescriptor::TYPE_SFIXED64: |
563 | 0 | case FieldDescriptor::TYPE_SINT64: |
564 | 0 | case FieldDescriptor::TYPE_INT64: |
565 | 0 | Traits::SetInt64(field, msg, 0); |
566 | 0 | break; |
567 | 0 | case FieldDescriptor::TYPE_FIXED64: |
568 | 0 | case FieldDescriptor::TYPE_UINT64: |
569 | 0 | Traits::SetUInt64(field, msg, 0); |
570 | 0 | break; |
571 | 0 | case FieldDescriptor::TYPE_SFIXED32: |
572 | 0 | case FieldDescriptor::TYPE_SINT32: |
573 | 0 | case FieldDescriptor::TYPE_INT32: |
574 | 0 | Traits::SetInt32(field, msg, 0); |
575 | 0 | break; |
576 | 0 | case FieldDescriptor::TYPE_FIXED32: |
577 | 0 | case FieldDescriptor::TYPE_UINT32: |
578 | 0 | Traits::SetUInt32(field, msg, 0); |
579 | 0 | break; |
580 | 0 | case FieldDescriptor::TYPE_BOOL: |
581 | 0 | Traits::SetBool(field, msg, false); |
582 | 0 | break; |
583 | 0 | case FieldDescriptor::TYPE_STRING: |
584 | 0 | case FieldDescriptor::TYPE_BYTES: |
585 | 0 | Traits::SetString(field, msg, ""); |
586 | 0 | break; |
587 | 0 | case FieldDescriptor::TYPE_ENUM: |
588 | 0 | Traits::SetEnum(field, msg, 0); |
589 | 0 | break; |
590 | 0 | case FieldDescriptor::TYPE_MESSAGE: |
591 | 0 | case FieldDescriptor::TYPE_GROUP: |
592 | 0 | return Traits::NewMsg(field, msg, |
593 | 0 | [](const auto&, const auto&) -> absl::Status { |
594 | 0 | return absl::OkStatus(); |
595 | 0 | }); Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::EmitNull<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Field, google::protobuf::json_internal::ParseProto2Descriptor::Msg&)::{lambda(auto:1 const&, auto:2 const&)#1}::operator()<google::protobuf::Descriptor, google::protobuf::json_internal::ParseProto2Descriptor::Msg>(google::protobuf::Descriptor const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg const&) const Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::EmitNull<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Field, google::protobuf::json_internal::ParseProto3Type::Msg&)::{lambda(auto:1 const&, auto:2 const&)#1}::operator()<google::protobuf::json_internal::ResolverPool::Message, google::protobuf::json_internal::ParseProto3Type::Msg>(google::protobuf::json_internal::ResolverPool::Message const&, google::protobuf::json_internal::ParseProto3Type::Msg const&) const |
596 | 0 | default: |
597 | 0 | return lex.Invalid( |
598 | 0 | absl::StrCat("unsupported field type: ", Traits::FieldType(field))); |
599 | 0 | } |
600 | 0 | return absl::OkStatus(); |
601 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::EmitNull<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Field, google::protobuf::json_internal::ParseProto2Descriptor::Msg&) Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::EmitNull<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Field, google::protobuf::json_internal::ParseProto3Type::Msg&) |
602 | | |
603 | | template <typename Traits> |
604 | 0 | absl::Status ParseArray(JsonLexer& lex, Field<Traits> field, Msg<Traits>& msg) { |
605 | 0 | if (lex.Peek(JsonLexer::kNull)) { |
606 | 0 | return lex.Expect("null"); |
607 | 0 | } |
608 | | |
609 | 0 | return lex.VisitArray([&]() -> absl::Status { |
610 | 0 | lex.path().NextRepeated(); |
611 | 0 | MessageType type = ClassifyMessage(Traits::FieldTypeName(field)); |
612 | |
|
613 | 0 | if (lex.Peek(JsonLexer::kNull)) { |
614 | 0 | if (type == MessageType::kValue) { |
615 | 0 | return ParseSingular<Traits>(lex, field, msg); |
616 | 0 | } |
617 | 0 | if (type == MessageType::kNull) { |
618 | 0 | return ParseSingular<Traits>(lex, field, msg); |
619 | 0 | } |
620 | | |
621 | 0 | if (lex.options().allow_legacy_syntax) { |
622 | 0 | RETURN_IF_ERROR(lex.Expect("null")); |
623 | 0 | return EmitNull<Traits>(lex, field, msg); |
624 | 0 | } |
625 | 0 | return lex.Invalid("null cannot occur inside of repeated fields"); |
626 | 0 | } |
627 | | |
628 | | // Note that this is sufficient to catch when we are inside of a ListValue, |
629 | | // because a ListValue's sole field is of type Value. Thus, we only need to |
630 | | // classify cases in which we are inside of an array and parsing messages |
631 | | // that like looking like arrays. |
632 | | // |
633 | | // This will also correctly handle e.g. writing out a ListValue with the |
634 | | // legacy syntax of `{"values": [[0], [1], [2]]}`, which does not go through |
635 | | // the custom parser handler. |
636 | 0 | bool can_flatten = |
637 | 0 | type != MessageType::kValue && type != MessageType::kList; |
638 | 0 | if (can_flatten && lex.options().allow_legacy_syntax && |
639 | 0 | lex.Peek(JsonLexer::kArr)) { |
640 | | // You read that right. In legacy mode, if we encounter an array within |
641 | | // an array, we just flatten it as part of the current array! |
642 | | // |
643 | | // This DOES NOT apply when parsing a google.protobuf.Value or a |
644 | | // google.protobuf.ListValue! |
645 | 0 | return ParseArray<Traits>(lex, field, msg); |
646 | 0 | } |
647 | 0 | return ParseSingular<Traits>(lex, field, msg); |
648 | 0 | }); Unexecuted instantiation: parser.cc:google::protobuf::json_internal::(anonymous namespace)::ParseArray<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Field, google::protobuf::json_internal::ParseProto2Descriptor::Msg&)::{lambda()#1}::operator()() const Unexecuted instantiation: parser.cc:google::protobuf::json_internal::(anonymous namespace)::ParseArray<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Field, google::protobuf::json_internal::ParseProto3Type::Msg&)::{lambda()#1}::operator()() const |
649 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseArray<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Field, google::protobuf::json_internal::ParseProto2Descriptor::Msg&) Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseArray<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Field, google::protobuf::json_internal::ParseProto3Type::Msg&) |
650 | | |
651 | | template <typename Traits> |
652 | 0 | absl::Status ParseMap(JsonLexer& lex, Field<Traits> field, Msg<Traits>& msg) { |
653 | 0 | if (lex.Peek(JsonLexer::kNull)) { |
654 | 0 | return lex.Expect("null"); |
655 | 0 | } |
656 | | |
657 | 0 | absl::flat_hash_set<std::string> keys_seen; |
658 | 0 | return lex.VisitObject( |
659 | 0 | [&](LocationWith<MaybeOwnedString>& key) -> absl::Status { |
660 | 0 | lex.path().NextRepeated(); |
661 | 0 | auto insert_result = keys_seen.emplace(key.value.AsView()); |
662 | 0 | if (!insert_result.second) { |
663 | 0 | return key.loc.Invalid(absl::StrFormat( |
664 | 0 | "got unexpectedly-repeated repeated map key: '%s'", |
665 | 0 | key.value.AsView())); |
666 | 0 | } |
667 | 0 | return Traits::NewMsg( |
668 | 0 | field, msg, |
669 | 0 | [&](const Desc<Traits>& type, Msg<Traits>& entry) -> absl::Status { |
670 | 0 | auto key_field = Traits::KeyField(type); |
671 | 0 | switch (Traits::FieldType(key_field)) { |
672 | 0 | case FieldDescriptor::TYPE_INT64: |
673 | 0 | case FieldDescriptor::TYPE_SINT64: |
674 | 0 | case FieldDescriptor::TYPE_SFIXED64: { |
675 | 0 | int64_t n; |
676 | 0 | if (!absl::SimpleAtoi(key.value.AsView(), &n)) { |
677 | 0 | return key.loc.Invalid( |
678 | 0 | "non-number characters in quoted number"); |
679 | 0 | } |
680 | 0 | Traits::SetInt64(key_field, entry, n); |
681 | 0 | break; |
682 | 0 | } |
683 | 0 | case FieldDescriptor::TYPE_UINT64: |
684 | 0 | case FieldDescriptor::TYPE_FIXED64: { |
685 | 0 | uint64_t n; |
686 | 0 | if (!absl::SimpleAtoi(key.value.AsView(), &n)) { |
687 | 0 | return key.loc.Invalid( |
688 | 0 | "non-number characters in quoted number"); |
689 | 0 | } |
690 | 0 | Traits::SetUInt64(key_field, entry, n); |
691 | 0 | break; |
692 | 0 | } |
693 | 0 | case FieldDescriptor::TYPE_INT32: |
694 | 0 | case FieldDescriptor::TYPE_SINT32: |
695 | 0 | case FieldDescriptor::TYPE_SFIXED32: { |
696 | 0 | int32_t n; |
697 | 0 | if (!absl::SimpleAtoi(key.value.AsView(), &n)) { |
698 | 0 | return key.loc.Invalid( |
699 | 0 | "non-number characters in quoted number"); |
700 | 0 | } |
701 | 0 | Traits::SetInt32(key_field, entry, n); |
702 | 0 | break; |
703 | 0 | } |
704 | 0 | case FieldDescriptor::TYPE_UINT32: |
705 | 0 | case FieldDescriptor::TYPE_FIXED32: { |
706 | 0 | uint32_t n; |
707 | 0 | if (!absl::SimpleAtoi(key.value.AsView(), &n)) { |
708 | 0 | return key.loc.Invalid( |
709 | 0 | "non-number characters in quoted number"); |
710 | 0 | } |
711 | 0 | Traits::SetUInt32(key_field, entry, n); |
712 | 0 | break; |
713 | 0 | } |
714 | 0 | case FieldDescriptor::TYPE_BOOL: { |
715 | 0 | if (key.value == "true") { |
716 | 0 | Traits::SetBool(key_field, entry, true); |
717 | 0 | } else if (key.value == "false") { |
718 | 0 | Traits::SetBool(key_field, entry, false); |
719 | 0 | } else { |
720 | 0 | return key.loc.Invalid(absl::StrFormat( |
721 | 0 | "expected bool string, got '%s'", key.value.AsView())); |
722 | 0 | } |
723 | 0 | break; |
724 | 0 | } |
725 | 0 | case FieldDescriptor::TYPE_ENUM: { |
726 | 0 | MaybeOwnedString key_str = key.value; |
727 | 0 | auto e = ParseEnumFromStr<Traits>(lex, key_str, field); |
728 | 0 | RETURN_IF_ERROR(e.status()); |
729 | 0 | Traits::SetEnum(key_field, entry, e->value_or(0)); |
730 | 0 | break; |
731 | 0 | } |
732 | 0 | case FieldDescriptor::TYPE_STRING: { |
733 | 0 | Traits::SetString(key_field, entry, |
734 | 0 | std::move(key.value.ToString())); |
735 | 0 | break; |
736 | 0 | } |
737 | 0 | default: |
738 | 0 | return lex.Invalid("unsupported map key type"); |
739 | 0 | } |
740 | | |
741 | 0 | return ParseSingular<Traits>(lex, Traits::ValueField(type), |
742 | 0 | entry); |
743 | 0 | }); Unexecuted instantiation: parser.cc:google::protobuf::json_internal::(anonymous namespace)::ParseMap<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Field, google::protobuf::json_internal::ParseProto2Descriptor::Msg&)::{lambda(google::protobuf::json_internal::LocationWith<google::protobuf::json_internal::MaybeOwnedString>&)#1}::operator()(google::protobuf::json_internal::LocationWith<google::protobuf::json_internal::MaybeOwnedString>&) const::{lambda(google::protobuf::Descriptor const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&)#1}::operator()(google::protobuf::Descriptor const, google::protobuf::json_internal::ParseProto2Descriptor::Msg) const Unexecuted instantiation: parser.cc:google::protobuf::json_internal::(anonymous namespace)::ParseMap<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Field, google::protobuf::json_internal::ParseProto3Type::Msg&)::{lambda(google::protobuf::json_internal::LocationWith<google::protobuf::json_internal::MaybeOwnedString>&)#1}::operator()(google::protobuf::json_internal::LocationWith<google::protobuf::json_internal::MaybeOwnedString>&) const::{lambda(google::protobuf::json_internal::ResolverPool::Message const&, google::protobuf::json_internal::ParseProto3Type::Msg&)#1}::operator()(google::protobuf::json_internal::ResolverPool::Message const, google::protobuf::json_internal::ParseProto3Type::Msg) const |
744 | 0 | }); Unexecuted instantiation: parser.cc:google::protobuf::json_internal::(anonymous namespace)::ParseMap<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Field, google::protobuf::json_internal::ParseProto2Descriptor::Msg&)::{lambda(google::protobuf::json_internal::LocationWith<google::protobuf::json_internal::MaybeOwnedString>&)#1}::operator()(google::protobuf::json_internal::LocationWith<google::protobuf::json_internal::MaybeOwnedString>&) const Unexecuted instantiation: parser.cc:google::protobuf::json_internal::(anonymous namespace)::ParseMap<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Field, google::protobuf::json_internal::ParseProto3Type::Msg&)::{lambda(google::protobuf::json_internal::LocationWith<google::protobuf::json_internal::MaybeOwnedString>&)#1}::operator()(google::protobuf::json_internal::LocationWith<google::protobuf::json_internal::MaybeOwnedString>&) const |
745 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseMap<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Field, google::protobuf::json_internal::ParseProto2Descriptor::Msg&) Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseMap<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Field, google::protobuf::json_internal::ParseProto3Type::Msg&) |
746 | | |
747 | | absl::optional<uint32_t> TakeTimeDigitsWithSuffixAndAdvance( |
748 | 0 | absl::string_view& data, int max_digits, absl::string_view end) { |
749 | 0 | ABSL_DCHECK_LE(max_digits, 9); |
750 | |
|
751 | 0 | uint32_t val = 0; |
752 | 0 | int limit = max_digits; |
753 | 0 | while (!data.empty()) { |
754 | 0 | if (limit-- < 0) { |
755 | 0 | return absl::nullopt; |
756 | 0 | } |
757 | 0 | uint32_t digit = data[0] - '0'; |
758 | 0 | if (digit >= 10) { |
759 | 0 | break; |
760 | 0 | } |
761 | | |
762 | 0 | val *= 10; |
763 | 0 | val += digit; |
764 | 0 | data = data.substr(1); |
765 | 0 | } |
766 | 0 | if (!absl::StartsWith(data, end)) { |
767 | 0 | return absl::nullopt; |
768 | 0 | } |
769 | | |
770 | 0 | data = data.substr(end.size()); |
771 | 0 | return val; |
772 | 0 | } |
773 | | |
774 | 0 | absl::optional<int32_t> TakeNanosAndAdvance(absl::string_view& data) { |
775 | 0 | int32_t frac_secs = 0; |
776 | 0 | size_t frac_digits = 0; |
777 | 0 | if (absl::StartsWith(data, ".")) { |
778 | 0 | for (char c : data.substr(1)) { |
779 | 0 | if (!absl::ascii_isdigit(c)) { |
780 | 0 | break; |
781 | 0 | } |
782 | 0 | ++frac_digits; |
783 | 0 | } |
784 | 0 | auto digits = data.substr(1, frac_digits); |
785 | 0 | if (frac_digits == 0 || frac_digits > 9 || |
786 | 0 | !absl::SimpleAtoi(digits, &frac_secs)) { |
787 | 0 | return absl::nullopt; |
788 | 0 | } |
789 | 0 | data = data.substr(frac_digits + 1); |
790 | 0 | } |
791 | 0 | for (int i = 0; i < 9 - frac_digits; ++i) { |
792 | 0 | frac_secs *= 10; |
793 | 0 | } |
794 | 0 | return frac_secs; |
795 | 0 | } |
796 | | |
797 | | template <typename Traits> |
798 | | absl::Status ParseTimestamp(JsonLexer& lex, const Desc<Traits>& desc, |
799 | 0 | Msg<Traits>& msg) { |
800 | 0 | if (lex.Peek(JsonLexer::kNull)) { |
801 | 0 | return lex.Expect("null"); |
802 | 0 | } |
803 | | |
804 | 0 | absl::StatusOr<LocationWith<MaybeOwnedString>> str = lex.ParseUtf8(); |
805 | 0 | RETURN_IF_ERROR(str.status()); |
806 | | |
807 | 0 | absl::string_view data = str->value.AsView(); |
808 | 0 | if (data.size() < 20) { |
809 | 0 | return str->loc.Invalid("timestamp string too short"); |
810 | 0 | } |
811 | | |
812 | 0 | int64_t secs; |
813 | 0 | { |
814 | | /* 1972-01-01T01:00:00 */ |
815 | 0 | auto year = TakeTimeDigitsWithSuffixAndAdvance(data, 4, "-"); |
816 | 0 | if (!year.has_value() || *year == 0) { |
817 | 0 | return str->loc.Invalid("bad year in timestamp"); |
818 | 0 | } |
819 | 0 | auto mon = TakeTimeDigitsWithSuffixAndAdvance(data, 2, "-"); |
820 | 0 | if (!mon.has_value() || *mon == 0) { |
821 | 0 | return str->loc.Invalid("bad month in timestamp"); |
822 | 0 | } |
823 | 0 | auto day = TakeTimeDigitsWithSuffixAndAdvance(data, 2, "T"); |
824 | 0 | if (!day.has_value() || *day == 0) { |
825 | 0 | return str->loc.Invalid("bad day in timestamp"); |
826 | 0 | } |
827 | 0 | auto hour = TakeTimeDigitsWithSuffixAndAdvance(data, 2, ":"); |
828 | 0 | if (!hour.has_value()) { |
829 | 0 | return str->loc.Invalid("bad hours in timestamp"); |
830 | 0 | } |
831 | 0 | auto min = TakeTimeDigitsWithSuffixAndAdvance(data, 2, ":"); |
832 | 0 | if (!min.has_value()) { |
833 | 0 | return str->loc.Invalid("bad minutes in timestamp"); |
834 | 0 | } |
835 | 0 | auto sec = TakeTimeDigitsWithSuffixAndAdvance(data, 2, ""); |
836 | 0 | if (!sec.has_value()) { |
837 | 0 | return str->loc.Invalid("bad seconds in timestamp"); |
838 | 0 | } |
839 | | |
840 | 0 | uint32_t m_adj = *mon - 3; // March-based month. |
841 | 0 | uint32_t carry = m_adj > *mon ? 1 : 0; |
842 | |
|
843 | 0 | uint32_t year_base = 4800; // Before min year, multiple of 400. |
844 | 0 | uint32_t y_adj = *year + year_base - carry; |
845 | |
|
846 | 0 | uint32_t month_days = ((m_adj + carry * 12) * 62719 + 769) / 2048; |
847 | 0 | uint32_t leap_days = y_adj / 4 - y_adj / 100 + y_adj / 400; |
848 | 0 | int32_t epoch_days = |
849 | 0 | y_adj * 365 + leap_days + month_days + (*day - 1) - 2472632; |
850 | |
|
851 | 0 | secs = int64_t{epoch_days} * 86400 + *hour * 3600 + *min * 60 + *sec; |
852 | 0 | } |
853 | | |
854 | 0 | auto nanos = TakeNanosAndAdvance(data); |
855 | 0 | if (!nanos.has_value()) { |
856 | 0 | return str->loc.Invalid("timestamp had bad nanoseconds"); |
857 | 0 | } |
858 | | |
859 | 0 | if (data.empty()) { |
860 | 0 | return str->loc.Invalid("timestamp missing timezone offset"); |
861 | 0 | } |
862 | | |
863 | 0 | { |
864 | | // [+-]hh:mm or Z |
865 | 0 | bool neg = false; |
866 | 0 | switch (data[0]) { |
867 | 0 | case '-': |
868 | 0 | neg = true; |
869 | 0 | ABSL_FALLTHROUGH_INTENDED; |
870 | 0 | case '+': { |
871 | 0 | if (data.size() != 6) { |
872 | 0 | return str->loc.Invalid("timestamp offset of wrong size."); |
873 | 0 | } |
874 | | |
875 | 0 | data = data.substr(1); |
876 | 0 | auto hour = TakeTimeDigitsWithSuffixAndAdvance(data, 2, ":"); |
877 | 0 | auto mins = TakeTimeDigitsWithSuffixAndAdvance(data, 2, ""); |
878 | 0 | if (!hour.has_value() || !mins.has_value()) { |
879 | 0 | return str->loc.Invalid("timestamp offset has bad hours and minutes"); |
880 | 0 | } |
881 | | |
882 | 0 | int64_t offset = (*hour * 60 + *mins) * 60; |
883 | 0 | secs += (neg ? offset : -offset); |
884 | 0 | break; |
885 | 0 | } |
886 | | // Lowercase z is not accepted, per the spec. |
887 | 0 | case 'Z': |
888 | 0 | if (data.size() == 1) { |
889 | 0 | break; |
890 | 0 | } |
891 | 0 | ABSL_FALLTHROUGH_INTENDED; |
892 | 0 | default: |
893 | 0 | return str->loc.Invalid("bad timezone offset"); |
894 | 0 | } |
895 | 0 | } |
896 | | |
897 | 0 | Traits::SetInt64(Traits::MustHaveField(desc, 1), msg, secs); |
898 | 0 | Traits::SetInt32(Traits::MustHaveField(desc, 2), msg, *nanos); |
899 | |
|
900 | 0 | return absl::OkStatus(); |
901 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseTimestamp<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Desc const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&) Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseTimestamp<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Desc const&, google::protobuf::json_internal::ParseProto3Type::Msg&) |
902 | | |
903 | | template <typename Traits> |
904 | | absl::Status ParseDuration(JsonLexer& lex, const Desc<Traits>& desc, |
905 | 0 | Msg<Traits>& msg) { |
906 | 0 | if (lex.Peek(JsonLexer::kNull)) { |
907 | 0 | return lex.Expect("null"); |
908 | 0 | } |
909 | | |
910 | 0 | constexpr int64_t kMaxSeconds = int64_t{3652500} * 86400; |
911 | |
|
912 | 0 | absl::StatusOr<LocationWith<MaybeOwnedString>> str = lex.ParseUtf8(); |
913 | 0 | RETURN_IF_ERROR(str.status()); |
914 | | |
915 | 0 | size_t int_part_end = 0; |
916 | 0 | for (char c : str->value.AsView()) { |
917 | 0 | if (!absl::ascii_isdigit(c) && c != '-') { |
918 | 0 | break; |
919 | 0 | } |
920 | 0 | ++int_part_end; |
921 | 0 | } |
922 | 0 | if (int_part_end == 0) { |
923 | 0 | return str->loc.Invalid("duration must start with an integer"); |
924 | 0 | } |
925 | | |
926 | 0 | absl::string_view sec_digits = str->value.AsView().substr(0, int_part_end); |
927 | 0 | int64_t secs; |
928 | 0 | if (!absl::SimpleAtoi(sec_digits, &secs)) { |
929 | 0 | return str->loc.Invalid("duration had bad seconds"); |
930 | 0 | } |
931 | | |
932 | 0 | if (secs > kMaxSeconds || secs < -kMaxSeconds) { |
933 | 0 | return str->loc.Invalid("duration out of range"); |
934 | 0 | } |
935 | | |
936 | 0 | absl::string_view rest = str->value.AsView().substr(int_part_end); |
937 | 0 | auto nanos = TakeNanosAndAdvance(rest); |
938 | 0 | if (!nanos.has_value()) { |
939 | 0 | return str->loc.Invalid("duration had bad nanoseconds"); |
940 | 0 | } |
941 | | |
942 | 0 | bool isNegative = (secs < 0) || absl::StartsWith(sec_digits, "-"); |
943 | 0 | if (isNegative) { |
944 | 0 | *nanos *= -1; |
945 | 0 | } |
946 | |
|
947 | 0 | if (rest != "s") { |
948 | 0 | return str->loc.Invalid("duration must end with a single 's'"); |
949 | 0 | } |
950 | | |
951 | 0 | Traits::SetInt64(Traits::MustHaveField(desc, 1), msg, secs); |
952 | 0 | Traits::SetInt32(Traits::MustHaveField(desc, 2), msg, *nanos); |
953 | |
|
954 | 0 | return absl::OkStatus(); |
955 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseDuration<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Desc const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&) Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseDuration<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Desc const&, google::protobuf::json_internal::ParseProto3Type::Msg&) |
956 | | |
957 | | template <typename Traits> |
958 | | absl::Status ParseFieldMask(JsonLexer& lex, const Desc<Traits>& desc, |
959 | 0 | Msg<Traits>& msg) { |
960 | 0 | absl::StatusOr<LocationWith<MaybeOwnedString>> str = lex.ParseUtf8(); |
961 | 0 | RETURN_IF_ERROR(str.status()); |
962 | 0 | auto paths = str->value.AsView(); |
963 | | |
964 | | // The special case of the empty string is not handled correctly below, |
965 | | // because StrSplit("", ',') is [""], not []. |
966 | 0 | if (paths.empty()) { |
967 | 0 | return absl::OkStatus(); |
968 | 0 | } |
969 | | |
970 | | // google.protobuf.FieldMask has a single field with number 1. |
971 | 0 | auto paths_field = Traits::MustHaveField(desc, 1); |
972 | 0 | for (absl::string_view path : absl::StrSplit(paths, ',')) { |
973 | 0 | std::string snake_path; |
974 | | // Assume approximately six-letter words, so add one extra space for an |
975 | | // underscore for every six bytes. |
976 | 0 | snake_path.reserve(path.size() * 7 / 6); |
977 | 0 | for (char c : path) { |
978 | 0 | if (absl::ascii_isdigit(c) || absl::ascii_islower(c) || c == '.') { |
979 | 0 | snake_path.push_back(c); |
980 | 0 | } else if (absl::ascii_isupper(c)) { |
981 | 0 | snake_path.push_back('_'); |
982 | 0 | snake_path.push_back(absl::ascii_tolower(c)); |
983 | 0 | } else if (lex.options().allow_legacy_syntax) { |
984 | 0 | snake_path.push_back(c); |
985 | 0 | } else { |
986 | 0 | return str->loc.Invalid("unexpected character in FieldMask"); |
987 | 0 | } |
988 | 0 | } |
989 | 0 | Traits::SetString(paths_field, msg, snake_path); |
990 | 0 | } |
991 | | |
992 | 0 | return absl::OkStatus(); |
993 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseFieldMask<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Desc const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&) Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseFieldMask<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Desc const&, google::protobuf::json_internal::ParseProto3Type::Msg&) |
994 | | |
995 | | template <typename Traits> |
996 | | absl::Status ParseAny(JsonLexer& lex, const Desc<Traits>& desc, |
997 | 0 | Msg<Traits>& msg) { |
998 | | // Buffer an entire object. Because @type can occur anywhere, we're forced |
999 | | // to do this. |
1000 | 0 | RETURN_IF_ERROR(lex.SkipToToken()); |
1001 | 0 | auto mark = lex.BeginMark(); |
1002 | | |
1003 | | // Search for @type, buffering the entire object along the way so we can |
1004 | | // reparse it. |
1005 | 0 | absl::optional<MaybeOwnedString> type_url; |
1006 | 0 | RETURN_IF_ERROR(lex.VisitObject( |
1007 | 0 | [&](const LocationWith<MaybeOwnedString>& key) -> absl::Status { |
1008 | 0 | if (key.value == "@type") { |
1009 | 0 | if (type_url.has_value()) { |
1010 | 0 | return key.loc.Invalid("repeated @type in Any"); |
1011 | 0 | } |
1012 | |
|
1013 | 0 | absl::StatusOr<LocationWith<MaybeOwnedString>> maybe_url = |
1014 | 0 | lex.ParseUtf8(); |
1015 | 0 | RETURN_IF_ERROR(maybe_url.status()); |
1016 | 0 | type_url = std::move(maybe_url)->value; |
1017 | 0 | return absl::OkStatus(); |
1018 | 0 | } |
1019 | 0 | return lex.SkipValue(); |
1020 | 0 | })); |
1021 | | |
1022 | | // Build a new lexer over the skipped object. |
1023 | 0 | absl::string_view any_text = mark.value.UpToUnread(); |
1024 | 0 | io::ArrayInputStream in(any_text.data(), any_text.size()); |
1025 | | // Copying lex.options() is important; it inherits the recursion |
1026 | | // limit. |
1027 | 0 | JsonLexer any_lex(&in, lex.options(), &lex.path(), mark.loc); |
1028 | |
|
1029 | 0 | if (!type_url.has_value() && !lex.options().allow_legacy_syntax) { |
1030 | 0 | return mark.loc.Invalid("missing @type in Any"); |
1031 | 0 | } |
1032 | | |
1033 | 0 | if (type_url.has_value()) { |
1034 | 0 | Traits::SetString(Traits::MustHaveField(desc, 1), msg, type_url->AsView()); |
1035 | 0 | return Traits::NewDynamic( |
1036 | 0 | Traits::MustHaveField(desc, 2), type_url->ToString(), msg, |
1037 | 0 | [&](const Desc<Traits>& desc, Msg<Traits>& msg) { |
1038 | 0 | auto pop = any_lex.path().Push("<any>", FieldDescriptor::TYPE_MESSAGE, |
1039 | 0 | Traits::TypeName(desc)); |
1040 | 0 | return ParseMessage<Traits>(any_lex, desc, msg, |
1041 | 0 | /*any_reparse=*/true); |
1042 | 0 | }); Unexecuted instantiation: parser.cc:google::protobuf::json_internal::(anonymous namespace)::ParseAny<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Desc const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&)::{lambda(google::protobuf::Descriptor const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&)#1}::operator()(google::protobuf::Descriptor const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&) const Unexecuted instantiation: parser.cc:google::protobuf::json_internal::(anonymous namespace)::ParseAny<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Desc const&, google::protobuf::json_internal::ParseProto3Type::Msg&)::{lambda(google::protobuf::json_internal::ResolverPool::Message const&, google::protobuf::json_internal::ParseProto3Type::Msg&)#1}::operator()(google::protobuf::json_internal::ResolverPool::Message const&, google::protobuf::json_internal::ParseProto3Type::Msg&) const |
1043 | 0 | } else { |
1044 | | // Empty {} is accepted in legacy mode. |
1045 | 0 | ABSL_DCHECK(lex.options().allow_legacy_syntax); |
1046 | 0 | RETURN_IF_ERROR(any_lex.VisitObject([&](auto&) { |
1047 | 0 | return mark.loc.Invalid( |
1048 | 0 | "in legacy mode, missing @type in Any is only allowed for an empty " |
1049 | 0 | "object"); |
1050 | 0 | })); |
1051 | 0 | return absl::OkStatus(); |
1052 | 0 | } |
1053 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseAny<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Desc const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&) Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseAny<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Desc const&, google::protobuf::json_internal::ParseProto3Type::Msg&) |
1054 | | |
1055 | | // These are mutually recursive with ParseValue. |
1056 | | template <typename Traits> |
1057 | | absl::Status ParseStructValue(JsonLexer& lex, const Desc<Traits>& desc, |
1058 | | Msg<Traits>& msg); |
1059 | | template <typename Traits> |
1060 | | absl::Status ParseListValue(JsonLexer& lex, const Desc<Traits>& desc, |
1061 | | Msg<Traits>& msg); |
1062 | | |
1063 | | template <typename Traits> |
1064 | | absl::Status ParseValue(JsonLexer& lex, const Desc<Traits>& desc, |
1065 | 0 | Msg<Traits>& msg) { |
1066 | 0 | auto kind = lex.PeekKind(); |
1067 | 0 | RETURN_IF_ERROR(kind.status()); |
1068 | | // NOTE: The field numbers 1 through 6 are the numbers of the oneof fields |
1069 | | // in google.protobuf.Value. Conformance tests verify the correctness of |
1070 | | // these numbers. |
1071 | 0 | switch (*kind) { |
1072 | 0 | case JsonLexer::kNull: { |
1073 | 0 | auto field = Traits::MustHaveField(desc, 1); |
1074 | 0 | auto pop = |
1075 | 0 | lex.path().Push(Traits::FieldName(field), Traits::FieldType(field), |
1076 | 0 | Traits::FieldTypeName(field)); |
1077 | |
|
1078 | 0 | RETURN_IF_ERROR(lex.Expect("null")); |
1079 | 0 | Traits::SetEnum(field, msg, 0); |
1080 | 0 | break; |
1081 | 0 | } |
1082 | 0 | case JsonLexer::kNum: { |
1083 | 0 | auto field = Traits::MustHaveField(desc, 2); |
1084 | 0 | auto pop = |
1085 | 0 | lex.path().Push(Traits::FieldName(field), Traits::FieldType(field), |
1086 | 0 | Traits::FieldTypeName(field)); |
1087 | |
|
1088 | 0 | auto number = lex.ParseNumber(); |
1089 | 0 | RETURN_IF_ERROR(number.status()); |
1090 | 0 | Traits::SetDouble(field, msg, number->value); |
1091 | 0 | break; |
1092 | 0 | } |
1093 | 0 | case JsonLexer::kStr: { |
1094 | 0 | auto field = Traits::MustHaveField(desc, 3); |
1095 | 0 | auto pop = |
1096 | 0 | lex.path().Push(Traits::FieldName(field), Traits::FieldType(field), |
1097 | 0 | Traits::FieldTypeName(field)); |
1098 | |
|
1099 | 0 | auto str = lex.ParseUtf8(); |
1100 | 0 | RETURN_IF_ERROR(str.status()); |
1101 | 0 | Traits::SetString(field, msg, std::move(str->value.ToString())); |
1102 | 0 | break; |
1103 | 0 | } |
1104 | 0 | case JsonLexer::kFalse: |
1105 | 0 | case JsonLexer::kTrue: { |
1106 | 0 | auto field = Traits::MustHaveField(desc, 4); |
1107 | 0 | auto pop = |
1108 | 0 | lex.path().Push(Traits::FieldName(field), Traits::FieldType(field), |
1109 | 0 | Traits::FieldTypeName(field)); |
1110 | | |
1111 | | // "Quoted" bools, including non-standard Abseil Atob bools, are not |
1112 | | // supported, because all strings are treated as genuine JSON strings. |
1113 | 0 | if (*kind == JsonLexer::kTrue) { |
1114 | 0 | RETURN_IF_ERROR(lex.Expect("true")); |
1115 | 0 | Traits::SetBool(field, msg, true); |
1116 | 0 | } else { |
1117 | 0 | RETURN_IF_ERROR(lex.Expect("false")); |
1118 | 0 | Traits::SetBool(field, msg, false); |
1119 | 0 | } |
1120 | 0 | break; |
1121 | 0 | } |
1122 | 0 | case JsonLexer::kObj: { |
1123 | 0 | auto field = Traits::MustHaveField(desc, 5); |
1124 | 0 | auto pop = |
1125 | 0 | lex.path().Push(Traits::FieldName(field), Traits::FieldType(field), |
1126 | 0 | Traits::FieldTypeName(field)); |
1127 | |
|
1128 | 0 | return Traits::NewMsg(field, msg, [&](auto& desc, auto& msg) { |
1129 | 0 | return ParseStructValue<Traits>(lex, desc, msg); |
1130 | 0 | }); Unexecuted instantiation: parser.cc:auto google::protobuf::json_internal::(anonymous namespace)::ParseValue<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Desc const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&)::{lambda(auto:1&, auto:2&)#1}::operator()<google::protobuf::Descriptor const, google::protobuf::json_internal::ParseProto2Descriptor::Msg>(google::protobuf::Descriptor const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&) const Unexecuted instantiation: parser.cc:auto google::protobuf::json_internal::(anonymous namespace)::ParseValue<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Desc const&, google::protobuf::json_internal::ParseProto3Type::Msg&)::{lambda(auto:1&, auto:2&)#1}::operator()<google::protobuf::json_internal::ResolverPool::Message const, google::protobuf::json_internal::ParseProto3Type::Msg>(google::protobuf::json_internal::ResolverPool::Message const&, google::protobuf::json_internal::ParseProto3Type::Msg&) const |
1131 | 0 | } |
1132 | 0 | case JsonLexer::kArr: { |
1133 | 0 | auto field = Traits::MustHaveField(desc, 6); |
1134 | 0 | auto pop = |
1135 | 0 | lex.path().Push(Traits::FieldName(field), Traits::FieldType(field), |
1136 | 0 | Traits::FieldTypeName(field)); |
1137 | |
|
1138 | 0 | return Traits::NewMsg(field, msg, [&](auto& desc, auto& msg) { |
1139 | 0 | return ParseListValue<Traits>(lex, desc, msg); |
1140 | 0 | }); Unexecuted instantiation: parser.cc:auto google::protobuf::json_internal::(anonymous namespace)::ParseValue<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Desc const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&)::{lambda(auto:1&, auto:2&)#2}::operator()<google::protobuf::Descriptor const, google::protobuf::json_internal::ParseProto2Descriptor::Msg>(google::protobuf::Descriptor const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&) const Unexecuted instantiation: parser.cc:auto google::protobuf::json_internal::(anonymous namespace)::ParseValue<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Desc const&, google::protobuf::json_internal::ParseProto3Type::Msg&)::{lambda(auto:1&, auto:2&)#2}::operator()<google::protobuf::json_internal::ResolverPool::Message const, google::protobuf::json_internal::ParseProto3Type::Msg>(google::protobuf::json_internal::ResolverPool::Message const&, google::protobuf::json_internal::ParseProto3Type::Msg&) const |
1141 | 0 | } |
1142 | 0 | } |
1143 | | |
1144 | 0 | return absl::OkStatus(); |
1145 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseValue<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Desc const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&) Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseValue<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Desc const&, google::protobuf::json_internal::ParseProto3Type::Msg&) |
1146 | | |
1147 | | template <typename Traits> |
1148 | | absl::Status ParseStructValue(JsonLexer& lex, const Desc<Traits>& desc, |
1149 | 0 | Msg<Traits>& msg) { |
1150 | 0 | auto entry_field = Traits::MustHaveField(desc, 1); |
1151 | 0 | auto pop = lex.path().Push("<struct>", FieldDescriptor::TYPE_MESSAGE, |
1152 | 0 | Traits::FieldTypeName(entry_field)); |
1153 | | |
1154 | | // Structs are always cleared even if set to {}. |
1155 | 0 | Traits::RecordAsSeen(entry_field, msg); |
1156 | | |
1157 | | // Parsing a map does the right thing: Struct has a single map<string, |
1158 | | // Value> field; keys are correctly parsed as strings, and the values |
1159 | | // recurse into ParseMessage, which will be routed into ParseValue. This |
1160 | | // results in some extra overhead, but performance is not what we're going |
1161 | | // for here. |
1162 | 0 | return ParseMap<Traits>(lex, entry_field, msg); |
1163 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseStructValue<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Desc const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&) Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseStructValue<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Desc const&, google::protobuf::json_internal::ParseProto3Type::Msg&) |
1164 | | |
1165 | | template <typename Traits> |
1166 | | absl::Status ParseListValue(JsonLexer& lex, const Desc<Traits>& desc, |
1167 | 0 | Msg<Traits>& msg) { |
1168 | 0 | auto entry_field = Traits::MustHaveField(desc, 1); |
1169 | 0 | auto pop = lex.path().Push("<list>", FieldDescriptor::TYPE_MESSAGE, |
1170 | 0 | Traits::FieldTypeName(entry_field)); |
1171 | | |
1172 | | // ListValues are always cleared even if set to []. |
1173 | 0 | Traits::RecordAsSeen(entry_field, msg); |
1174 | | // Parsing an array does the right thing: see the analogous comment in |
1175 | | // ParseStructValue. |
1176 | 0 | return ParseArray<Traits>(lex, entry_field, msg); |
1177 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseListValue<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Desc const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&) Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseListValue<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Desc const&, google::protobuf::json_internal::ParseProto3Type::Msg&) |
1178 | | |
1179 | | template <typename Traits> |
1180 | | absl::Status ParseField(JsonLexer& lex, const Desc<Traits>& desc, |
1181 | 0 | absl::string_view name, Msg<Traits>& msg) { |
1182 | 0 | absl::optional<Field<Traits>> field; |
1183 | 0 | if (absl::StartsWith(name, "[") && absl::EndsWith(name, "]")) { |
1184 | 0 | absl::string_view extn_name = name.substr(1, name.size() - 2); |
1185 | 0 | field = Traits::ExtensionByName(desc, extn_name); |
1186 | |
|
1187 | 0 | if (field.has_value()) { |
1188 | | // The check for whether this is an invalid field occurs below, since it |
1189 | | // is combined for both extension and non-extension fields. |
1190 | 0 | auto correct_type_name = Traits::TypeName(desc); |
1191 | 0 | if (Traits::TypeName(Traits::ContainingType(*field)) != |
1192 | 0 | correct_type_name) { |
1193 | 0 | return lex.Invalid(absl::StrFormat( |
1194 | 0 | "'%s' is a known extension name, but is not an extension " |
1195 | 0 | "of '%s' as expected", |
1196 | 0 | extn_name, correct_type_name)); |
1197 | 0 | } |
1198 | 0 | } |
1199 | 0 | } else { |
1200 | 0 | field = Traits::FieldByName(desc, name); |
1201 | 0 | } |
1202 | | |
1203 | 0 | if (!field.has_value()) { |
1204 | 0 | if (!lex.options().ignore_unknown_fields) { |
1205 | 0 | return lex.Invalid(absl::StrFormat("no such field: '%s'", name)); |
1206 | 0 | } |
1207 | 0 | return lex.SkipValue(); |
1208 | 0 | } |
1209 | | |
1210 | 0 | auto pop = lex.path().Push(name, Traits::FieldType(*field), |
1211 | 0 | Traits::FieldTypeName(*field)); |
1212 | |
|
1213 | 0 | if (Traits::HasParsed( |
1214 | 0 | *field, msg, |
1215 | 0 | /*allow_repeated_non_oneof=*/lex.options().allow_legacy_syntax) && |
1216 | 0 | !lex.Peek(JsonLexer::kNull)) { |
1217 | 0 | return lex.Invalid(absl::StrFormat( |
1218 | 0 | "'%s' has already been set (either directly or as part of a oneof)", |
1219 | 0 | name)); |
1220 | 0 | } |
1221 | | |
1222 | 0 | if (Traits::IsMap(*field)) { |
1223 | 0 | return ParseMap<Traits>(lex, *field, msg); |
1224 | 0 | } |
1225 | | |
1226 | 0 | if (Traits::IsRepeated(*field)) { |
1227 | 0 | if (lex.options().allow_legacy_syntax && !lex.Peek(JsonLexer::kArr)) { |
1228 | | // The original ESF parser permits a single element in place of an array |
1229 | | // thereof. |
1230 | 0 | return ParseSingular<Traits>(lex, *field, msg); |
1231 | 0 | } |
1232 | 0 | return ParseArray<Traits>(lex, *field, msg); |
1233 | 0 | } |
1234 | | |
1235 | 0 | return ParseSingular<Traits>(lex, *field, msg); |
1236 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseField<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Desc const&, absl::lts_20230125::string_view, google::protobuf::json_internal::ParseProto2Descriptor::Msg&) Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseField<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Desc const&, absl::lts_20230125::string_view, google::protobuf::json_internal::ParseProto3Type::Msg&) |
1237 | | |
1238 | | template <typename Traits> |
1239 | | absl::Status ParseMessage(JsonLexer& lex, const Desc<Traits>& desc, |
1240 | 0 | Msg<Traits>& msg, bool any_reparse) { |
1241 | 0 | MessageType type = ClassifyMessage(Traits::TypeName(desc)); |
1242 | 0 | if (!any_reparse) { |
1243 | 0 | switch (type) { |
1244 | 0 | case MessageType::kAny: |
1245 | 0 | return ParseAny<Traits>(lex, desc, msg); |
1246 | 0 | case MessageType::kValue: |
1247 | 0 | return ParseValue<Traits>(lex, desc, msg); |
1248 | 0 | case MessageType::kStruct: |
1249 | 0 | return ParseStructValue<Traits>(lex, desc, msg); |
1250 | 0 | default: |
1251 | 0 | break; |
1252 | 0 | } |
1253 | | // For some types, the ESF parser permits parsing the "non-special" version. |
1254 | | // It is not clear if this counts as out-of-spec, but we're treating it as |
1255 | | // such. |
1256 | 0 | bool is_upcoming_object = lex.Peek(JsonLexer::kObj); |
1257 | 0 | if (!(is_upcoming_object && lex.options().allow_legacy_syntax)) { |
1258 | 0 | switch (type) { |
1259 | 0 | case MessageType::kList: |
1260 | 0 | return ParseListValue<Traits>(lex, desc, msg); |
1261 | 0 | case MessageType::kWrapper: { |
1262 | 0 | return ParseSingular<Traits>(lex, Traits::MustHaveField(desc, 1), |
1263 | 0 | msg); |
1264 | 0 | } |
1265 | 0 | case MessageType::kTimestamp: |
1266 | 0 | return ParseTimestamp<Traits>(lex, desc, msg); |
1267 | 0 | case MessageType::kDuration: |
1268 | 0 | return ParseDuration<Traits>(lex, desc, msg); |
1269 | 0 | case MessageType::kFieldMask: |
1270 | 0 | return ParseFieldMask<Traits>(lex, desc, msg); |
1271 | 0 | default: |
1272 | 0 | break; |
1273 | 0 | } |
1274 | 0 | } |
1275 | 0 | } |
1276 | | |
1277 | 0 | return lex.VisitObject( |
1278 | 0 | [&](LocationWith<MaybeOwnedString>& name) -> absl::Status { |
1279 | | // If this is a well-known type, we expect its contents to be inside |
1280 | | // of a JSON field named "value". |
1281 | 0 | if (any_reparse) { |
1282 | 0 | if (name.value == "@type") { |
1283 | 0 | RETURN_IF_ERROR(lex.SkipValue()); |
1284 | 0 | return absl::OkStatus(); |
1285 | 0 | } |
1286 | 0 | if (type != MessageType::kNotWellKnown) { |
1287 | 0 | if (name.value != "value") { |
1288 | 0 | return lex.Invalid( |
1289 | 0 | "fields in a well-known-typed Any must be @type or value"); |
1290 | 0 | } |
1291 | | // Parse the upcoming value as the message itself. This is *not* |
1292 | | // an Any reparse because we do not expect to see @type in the |
1293 | | // upcoming value. |
1294 | 0 | return ParseMessage<Traits>(lex, desc, msg, |
1295 | 0 | /*any_reparse=*/false); |
1296 | 0 | } |
1297 | 0 | } |
1298 | | |
1299 | 0 | return ParseField<Traits>(lex, desc, name.value.AsView(), msg); |
1300 | 0 | }); Unexecuted instantiation: parser.cc:google::protobuf::json_internal::(anonymous namespace)::ParseMessage<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Desc const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&, bool)::{lambda(google::protobuf::json_internal::LocationWith<google::protobuf::json_internal::MaybeOwnedString>&)#1}::operator()(google::protobuf::json_internal::LocationWith<google::protobuf::json_internal::MaybeOwnedString>&) const Unexecuted instantiation: parser.cc:google::protobuf::json_internal::(anonymous namespace)::ParseMessage<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Desc const&, google::protobuf::json_internal::ParseProto3Type::Msg&, bool)::{lambda(google::protobuf::json_internal::LocationWith<google::protobuf::json_internal::MaybeOwnedString>&)#1}::operator()(google::protobuf::json_internal::LocationWith<google::protobuf::json_internal::MaybeOwnedString>&) const |
1301 | 0 | } Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseMessage<google::protobuf::json_internal::ParseProto2Descriptor>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto2Descriptor::Desc const&, google::protobuf::json_internal::ParseProto2Descriptor::Msg&, bool) Unexecuted instantiation: parser.cc:absl::lts_20230125::Status google::protobuf::json_internal::(anonymous namespace)::ParseMessage<google::protobuf::json_internal::ParseProto3Type>(google::protobuf::json_internal::JsonLexer&, google::protobuf::json_internal::ParseProto3Type::Desc const&, google::protobuf::json_internal::ParseProto3Type::Msg&, bool) |
1302 | | } // namespace |
1303 | | |
1304 | | absl::Status JsonStringToMessage(absl::string_view input, Message* message, |
1305 | 0 | json_internal::ParseOptions options) { |
1306 | 0 | MessagePath path(message->GetDescriptor()->full_name()); |
1307 | 0 | if (PROTOBUF_DEBUG) { |
1308 | 0 | ABSL_DLOG(INFO) << "json2/input: " << absl::CHexEscape(input); |
1309 | 0 | } |
1310 | 0 | io::ArrayInputStream in(input.data(), input.size()); |
1311 | 0 | JsonLexer lex(&in, options, &path); |
1312 | |
|
1313 | 0 | ParseProto2Descriptor::Msg msg(message); |
1314 | 0 | absl::Status s = |
1315 | 0 | ParseMessage<ParseProto2Descriptor>(lex, *message->GetDescriptor(), msg, |
1316 | 0 | /*any_reparse=*/false); |
1317 | 0 | if (s.ok() && !lex.AtEof()) { |
1318 | 0 | s = absl::InvalidArgumentError( |
1319 | 0 | "extraneous characters after end of JSON object"); |
1320 | 0 | } |
1321 | |
|
1322 | 0 | if (PROTOBUF_DEBUG) { |
1323 | 0 | ABSL_DLOG(INFO) << "json2/status: " << s; |
1324 | 0 | ABSL_DLOG(INFO) << "json2/output: " << message->DebugString(); |
1325 | 0 | } |
1326 | 0 | return s; |
1327 | 0 | } |
1328 | | |
1329 | | absl::Status JsonToBinaryStream(google::protobuf::util::TypeResolver* resolver, |
1330 | | const std::string& type_url, |
1331 | | io::ZeroCopyInputStream* json_input, |
1332 | | io::ZeroCopyOutputStream* binary_output, |
1333 | 0 | json_internal::ParseOptions options) { |
1334 | | // NOTE: Most of the contortions in this function are to allow for capture of |
1335 | | // input and output of the parser in ABSL_DLOG mode. Destruction order is very |
1336 | | // critical in this function, because io::ZeroCopy*Stream types usually only |
1337 | | // flush on destruction. |
1338 | | |
1339 | | // For ABSL_DLOG, we would like to print out the input and output, which |
1340 | | // requires buffering both instead of doing "zero copy". This block, and the |
1341 | | // one at the end of the function, set up and tear down interception of the |
1342 | | // input and output streams. |
1343 | 0 | std::string copy; |
1344 | 0 | std::string out; |
1345 | 0 | absl::optional<io::ArrayInputStream> tee_input; |
1346 | 0 | absl::optional<io::StringOutputStream> tee_output; |
1347 | 0 | if (PROTOBUF_DEBUG) { |
1348 | 0 | const void* data; |
1349 | 0 | int len; |
1350 | 0 | while (json_input->Next(&data, &len)) { |
1351 | 0 | copy.resize(copy.size() + len); |
1352 | 0 | std::memcpy(©[copy.size() - len], data, len); |
1353 | 0 | } |
1354 | 0 | tee_input.emplace(copy.data(), copy.size()); |
1355 | 0 | tee_output.emplace(&out); |
1356 | 0 | ABSL_DLOG(INFO) << "json2/input: " << absl::CHexEscape(copy); |
1357 | 0 | } |
1358 | | |
1359 | | // This scope forces the CodedOutputStream inside of `msg` to flush before we |
1360 | | // possibly handle logging the binary protobuf output. |
1361 | 0 | absl::Status s; |
1362 | 0 | { |
1363 | 0 | MessagePath path(type_url); |
1364 | 0 | JsonLexer lex(tee_input.has_value() ? &*tee_input : json_input, options, |
1365 | 0 | &path); |
1366 | 0 | Msg<ParseProto3Type> msg(tee_output.has_value() ? &*tee_output |
1367 | 0 | : binary_output); |
1368 | |
|
1369 | 0 | ResolverPool pool(resolver); |
1370 | 0 | auto desc = pool.FindMessage(type_url); |
1371 | 0 | RETURN_IF_ERROR(desc.status()); |
1372 | | |
1373 | 0 | s = ParseMessage<ParseProto3Type>(lex, **desc, msg, /*any_reparse=*/false); |
1374 | 0 | if (s.ok() && !lex.AtEof()) { |
1375 | 0 | s = absl::InvalidArgumentError( |
1376 | 0 | "extraneous characters after end of JSON object"); |
1377 | 0 | } |
1378 | 0 | } |
1379 | | |
1380 | 0 | if (PROTOBUF_DEBUG) { |
1381 | 0 | tee_output.reset(); // Flush the output stream. |
1382 | 0 | io::zc_sink_internal::ZeroCopyStreamByteSink(binary_output) |
1383 | 0 | .Append(out.data(), out.size()); |
1384 | 0 | ABSL_DLOG(INFO) << "json2/status: " << s; |
1385 | 0 | ABSL_DLOG(INFO) << "json2/output: " << absl::BytesToHexString(out); |
1386 | 0 | } |
1387 | |
|
1388 | 0 | return s; |
1389 | 0 | } |
1390 | | } // namespace json_internal |
1391 | | } // namespace protobuf |
1392 | | } // namespace google |