TLA Line data Source code
1 : //
2 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 : // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
4 : //
5 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 : //
8 : // Official repository: https://github.com/boostorg/json
9 : //
10 :
11 : #ifndef BOOST_JSON_BASIC_PARSER_IMPL_HPP
12 : #define BOOST_JSON_BASIC_PARSER_IMPL_HPP
13 :
14 : #include <boost/json/detail/config.hpp>
15 : #include <boost/json/detail/literals.hpp>
16 : #include <boost/json/basic_parser.hpp>
17 : #include <boost/json/error.hpp>
18 : #include <boost/json/detail/buffer.hpp>
19 : #include <boost/json/detail/charconv/from_chars.hpp>
20 : #include <boost/json/detail/sse2.hpp>
21 : #include <boost/mp11/algorithm.hpp>
22 : #include <boost/mp11/integral.hpp>
23 : #include <cmath>
24 : #include <limits>
25 : #include <cstring>
26 :
27 : #ifdef _MSC_VER
28 : #pragma warning(push)
29 : #pragma warning(disable: 4702) // unreachable code
30 : #pragma warning(disable: 4127) // conditional expression is constant
31 : #endif
32 :
33 : /* This file must be manually included to get the
34 : function template definitions for basic_parser.
35 : */
36 :
37 : /* Reference:
38 :
39 : https://www.json.org/
40 :
41 : RFC 7159: The JavaScript Object Notation (JSON) Data Interchange Format
42 : https://tools.ietf.org/html/rfc7159
43 :
44 : https://ampl.com/netlib/fp/dtoa.c
45 : */
46 :
47 : #ifndef BOOST_JSON_DOCS
48 :
49 : namespace boost {
50 : namespace json {
51 : namespace detail {
52 :
53 : inline
54 : double
55 HIT 1035607 : pow10(int exp) noexcept
56 : {
57 : static double const tab[618] = {
58 : 1e-308, 1e-307, 1e-306, 1e-305, 1e-304, 1e-303, 1e-302, 1e-301,
59 :
60 : 1e-300, 1e-299, 1e-298, 1e-297, 1e-296, 1e-295, 1e-294, 1e-293, 1e-292, 1e-291,
61 : 1e-290, 1e-289, 1e-288, 1e-287, 1e-286, 1e-285, 1e-284, 1e-283, 1e-282, 1e-281,
62 : 1e-280, 1e-279, 1e-278, 1e-277, 1e-276, 1e-275, 1e-274, 1e-273, 1e-272, 1e-271,
63 : 1e-270, 1e-269, 1e-268, 1e-267, 1e-266, 1e-265, 1e-264, 1e-263, 1e-262, 1e-261,
64 : 1e-260, 1e-259, 1e-258, 1e-257, 1e-256, 1e-255, 1e-254, 1e-253, 1e-252, 1e-251,
65 : 1e-250, 1e-249, 1e-248, 1e-247, 1e-246, 1e-245, 1e-244, 1e-243, 1e-242, 1e-241,
66 : 1e-240, 1e-239, 1e-238, 1e-237, 1e-236, 1e-235, 1e-234, 1e-233, 1e-232, 1e-231,
67 : 1e-230, 1e-229, 1e-228, 1e-227, 1e-226, 1e-225, 1e-224, 1e-223, 1e-222, 1e-221,
68 : 1e-220, 1e-219, 1e-218, 1e-217, 1e-216, 1e-215, 1e-214, 1e-213, 1e-212, 1e-211,
69 : 1e-210, 1e-209, 1e-208, 1e-207, 1e-206, 1e-205, 1e-204, 1e-203, 1e-202, 1e-201,
70 :
71 : 1e-200, 1e-199, 1e-198, 1e-197, 1e-196, 1e-195, 1e-194, 1e-193, 1e-192, 1e-191,
72 : 1e-190, 1e-189, 1e-188, 1e-187, 1e-186, 1e-185, 1e-184, 1e-183, 1e-182, 1e-181,
73 : 1e-180, 1e-179, 1e-178, 1e-177, 1e-176, 1e-175, 1e-174, 1e-173, 1e-172, 1e-171,
74 : 1e-170, 1e-169, 1e-168, 1e-167, 1e-166, 1e-165, 1e-164, 1e-163, 1e-162, 1e-161,
75 : 1e-160, 1e-159, 1e-158, 1e-157, 1e-156, 1e-155, 1e-154, 1e-153, 1e-152, 1e-151,
76 : 1e-150, 1e-149, 1e-148, 1e-147, 1e-146, 1e-145, 1e-144, 1e-143, 1e-142, 1e-141,
77 : 1e-140, 1e-139, 1e-138, 1e-137, 1e-136, 1e-135, 1e-134, 1e-133, 1e-132, 1e-131,
78 : 1e-130, 1e-129, 1e-128, 1e-127, 1e-126, 1e-125, 1e-124, 1e-123, 1e-122, 1e-121,
79 : 1e-120, 1e-119, 1e-118, 1e-117, 1e-116, 1e-115, 1e-114, 1e-113, 1e-112, 1e-111,
80 : 1e-110, 1e-109, 1e-108, 1e-107, 1e-106, 1e-105, 1e-104, 1e-103, 1e-102, 1e-101,
81 :
82 : 1e-100, 1e-099, 1e-098, 1e-097, 1e-096, 1e-095, 1e-094, 1e-093, 1e-092, 1e-091,
83 : 1e-090, 1e-089, 1e-088, 1e-087, 1e-086, 1e-085, 1e-084, 1e-083, 1e-082, 1e-081,
84 : 1e-080, 1e-079, 1e-078, 1e-077, 1e-076, 1e-075, 1e-074, 1e-073, 1e-072, 1e-071,
85 : 1e-070, 1e-069, 1e-068, 1e-067, 1e-066, 1e-065, 1e-064, 1e-063, 1e-062, 1e-061,
86 : 1e-060, 1e-059, 1e-058, 1e-057, 1e-056, 1e-055, 1e-054, 1e-053, 1e-052, 1e-051,
87 : 1e-050, 1e-049, 1e-048, 1e-047, 1e-046, 1e-045, 1e-044, 1e-043, 1e-042, 1e-041,
88 : 1e-040, 1e-039, 1e-038, 1e-037, 1e-036, 1e-035, 1e-034, 1e-033, 1e-032, 1e-031,
89 : 1e-030, 1e-029, 1e-028, 1e-027, 1e-026, 1e-025, 1e-024, 1e-023, 1e-022, 1e-021,
90 : 1e-020, 1e-019, 1e-018, 1e-017, 1e-016, 1e-015, 1e-014, 1e-013, 1e-012, 1e-011,
91 : 1e-010, 1e-009, 1e-008, 1e-007, 1e-006, 1e-005, 1e-004, 1e-003, 1e-002, 1e-001,
92 :
93 : 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009,
94 : 1e+010, 1e+011, 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019,
95 : 1e+020, 1e+021, 1e+022, 1e+023, 1e+024, 1e+025, 1e+026, 1e+027, 1e+028, 1e+029,
96 : 1e+030, 1e+031, 1e+032, 1e+033, 1e+034, 1e+035, 1e+036, 1e+037, 1e+038, 1e+039,
97 : 1e+040, 1e+041, 1e+042, 1e+043, 1e+044, 1e+045, 1e+046, 1e+047, 1e+048, 1e+049,
98 : 1e+050, 1e+051, 1e+052, 1e+053, 1e+054, 1e+055, 1e+056, 1e+057, 1e+058, 1e+059,
99 : 1e+060, 1e+061, 1e+062, 1e+063, 1e+064, 1e+065, 1e+066, 1e+067, 1e+068, 1e+069,
100 : 1e+070, 1e+071, 1e+072, 1e+073, 1e+074, 1e+075, 1e+076, 1e+077, 1e+078, 1e+079,
101 : 1e+080, 1e+081, 1e+082, 1e+083, 1e+084, 1e+085, 1e+086, 1e+087, 1e+088, 1e+089,
102 : 1e+090, 1e+091, 1e+092, 1e+093, 1e+094, 1e+095, 1e+096, 1e+097, 1e+098, 1e+099,
103 :
104 : 1e+100, 1e+101, 1e+102, 1e+103, 1e+104, 1e+105, 1e+106, 1e+107, 1e+108, 1e+109,
105 : 1e+110, 1e+111, 1e+112, 1e+113, 1e+114, 1e+115, 1e+116, 1e+117, 1e+118, 1e+119,
106 : 1e+120, 1e+121, 1e+122, 1e+123, 1e+124, 1e+125, 1e+126, 1e+127, 1e+128, 1e+129,
107 : 1e+130, 1e+131, 1e+132, 1e+133, 1e+134, 1e+135, 1e+136, 1e+137, 1e+138, 1e+139,
108 : 1e+140, 1e+141, 1e+142, 1e+143, 1e+144, 1e+145, 1e+146, 1e+147, 1e+148, 1e+149,
109 : 1e+150, 1e+151, 1e+152, 1e+153, 1e+154, 1e+155, 1e+156, 1e+157, 1e+158, 1e+159,
110 : 1e+160, 1e+161, 1e+162, 1e+163, 1e+164, 1e+165, 1e+166, 1e+167, 1e+168, 1e+169,
111 : 1e+170, 1e+171, 1e+172, 1e+173, 1e+174, 1e+175, 1e+176, 1e+177, 1e+178, 1e+179,
112 : 1e+180, 1e+181, 1e+182, 1e+183, 1e+184, 1e+185, 1e+186, 1e+187, 1e+188, 1e+189,
113 : 1e+190, 1e+191, 1e+192, 1e+193, 1e+194, 1e+195, 1e+196, 1e+197, 1e+198, 1e+199,
114 :
115 : 1e+200, 1e+201, 1e+202, 1e+203, 1e+204, 1e+205, 1e+206, 1e+207, 1e+208, 1e+209,
116 : 1e+210, 1e+211, 1e+212, 1e+213, 1e+214, 1e+215, 1e+216, 1e+217, 1e+218, 1e+219,
117 : 1e+220, 1e+221, 1e+222, 1e+223, 1e+224, 1e+225, 1e+226, 1e+227, 1e+228, 1e+229,
118 : 1e+230, 1e+231, 1e+232, 1e+233, 1e+234, 1e+235, 1e+236, 1e+237, 1e+238, 1e+239,
119 : 1e+240, 1e+241, 1e+242, 1e+243, 1e+244, 1e+245, 1e+246, 1e+247, 1e+248, 1e+249,
120 : 1e+250, 1e+251, 1e+252, 1e+253, 1e+254, 1e+255, 1e+256, 1e+257, 1e+258, 1e+259,
121 : 1e+260, 1e+261, 1e+262, 1e+263, 1e+264, 1e+265, 1e+266, 1e+267, 1e+268, 1e+269,
122 : 1e+270, 1e+271, 1e+272, 1e+273, 1e+274, 1e+275, 1e+276, 1e+277, 1e+278, 1e+279,
123 : 1e+280, 1e+281, 1e+282, 1e+283, 1e+284, 1e+285, 1e+286, 1e+287, 1e+288, 1e+289,
124 : 1e+290, 1e+291, 1e+292, 1e+293, 1e+294, 1e+295, 1e+296, 1e+297, 1e+298, 1e+299,
125 :
126 : 1e+300, 1e+301, 1e+302, 1e+303, 1e+304, 1e+305, 1e+306, 1e+307, 1e+308 };
127 :
128 1035607 : if( exp > 308 )
129 : {
130 455 : return std::numeric_limits<double>::infinity();
131 : }
132 1035152 : else if( exp < -308 )
133 : {
134 : // due to the way pow10 is used by dec_to_float,
135 : // we can afford to return 0.0 here
136 151 : return 0.0;
137 : }
138 : else
139 : {
140 1035001 : exp += 308;
141 1035001 : BOOST_ASSERT(exp >= 0 && exp < 618);
142 1035001 : return tab[exp];
143 : }
144 : }
145 :
146 : inline
147 : double
148 1043157 : dec_to_float(
149 : std::uint64_t m,
150 : std::int32_t e,
151 : bool neg) noexcept
152 : {
153 : // convert to double explicitly to silence warnings
154 1043157 : double x = static_cast<double>(m);
155 1043157 : if(neg)
156 17069 : x = -x;
157 :
158 : // pow10 returns infinity for large exponents,
159 : // and zero times infinity is NaN
160 1043157 : if(m == 0)
161 7550 : return x;
162 :
163 1035607 : if(e < -305)
164 : {
165 5269 : x *= 1e-305 ;
166 5269 : e += 305;
167 : }
168 :
169 1035607 : if(e >= -22 && e < 0)
170 57637 : return x / pow10(-e);
171 :
172 977970 : return x * pow10(e);
173 : }
174 :
175 : inline
176 : bool
177 : is_control(char c) noexcept
178 : {
179 : return static_cast<unsigned char>(c) < 32;
180 : }
181 :
182 : inline
183 : int
184 66931 : hex_digit(unsigned char c) noexcept
185 : {
186 : // by Peter Dimov
187 66931 : if( c >= '0' && c <= '9' )
188 35759 : return c - '0';
189 31172 : c &= ~0x20;
190 31172 : if( c >= 'A' && c <= 'F' )
191 30562 : return 10 + c - 'A';
192 610 : return -1;
193 : }
194 :
195 : } // detail
196 :
197 : //----------------------------------------------------------
198 :
199 : template< class Handler >
200 : template< bool StackEmpty_, char First_ >
201 : struct basic_parser<Handler>::
202 : parse_number_helper
203 : {
204 : basic_parser* parser;
205 : char const* p;
206 :
207 : template< std::size_t N >
208 : char const*
209 10515990 : operator()( mp11::mp_size_t<N> ) const
210 : {
211 21026475 : return parser->parse_number(
212 10515990 : p,
213 : std::integral_constant<bool, StackEmpty_>(),
214 : std::integral_constant<char, First_>(),
215 : std::integral_constant<
216 10510486 : number_precision, static_cast<number_precision>(N)>() );
217 : }
218 : };
219 :
220 : //----------------------------------------------------------
221 :
222 : template<class Handler>
223 : void
224 8602432 : basic_parser<Handler>::
225 : reserve()
226 : {
227 8602432 : if(BOOST_JSON_LIKELY(
228 : ! st_.empty()))
229 37477 : return;
230 : // Reserve the largest stack we need,
231 : // to avoid reallocation during suspend.
232 17129910 : st_.reserve(
233 : sizeof(state) + // document parsing state
234 : (sizeof(state) +
235 8564955 : sizeof(std::size_t)) * depth() + // array and object state + size
236 : sizeof(state) + // value parsing state
237 : sizeof(std::size_t) + // string size
238 : sizeof(state)); // comment state
239 : }
240 :
241 : //----------------------------------------------------------
242 : //
243 : // The sentinel value is returned by parse functions
244 : // to indicate that the parser failed, or suspended.
245 : // this is used as it is distinct from all valid values
246 : // for data in write
247 :
248 : template<class Handler>
249 : const char*
250 47301147 : basic_parser<Handler>::
251 : sentinel()
252 : {
253 : // the "+1" ensures that the returned pointer is unique even if
254 : // the given input buffer borders on this object
255 : return reinterpret_cast<
256 47301147 : const char*>(this) + 1;
257 : }
258 :
259 : template<class Handler>
260 : bool
261 10851991 : basic_parser<Handler>::
262 : incomplete(
263 : const detail::const_stream_wrapper& cs)
264 : {
265 10851991 : return cs.begin() == sentinel();
266 : }
267 :
268 : //----------------------------------------------------------
269 : //
270 : // These functions are declared with the BOOST_NOINLINE
271 : // attribute to avoid polluting the parsers hot-path.
272 : // They return the canary value to indicate suspension
273 : // or failure.
274 :
275 : template<class Handler>
276 : const char*
277 : basic_parser<Handler>::
278 : suspend_or_fail(state st)
279 : {
280 : if(BOOST_JSON_LIKELY(
281 : ! ec_ && more_))
282 : {
283 : // suspend
284 : reserve();
285 : st_.push_unchecked(st);
286 : }
287 : return sentinel();
288 : }
289 :
290 : template<class Handler>
291 : const char*
292 56179 : basic_parser<Handler>::
293 : suspend_or_fail(
294 : state st,
295 : std::size_t n)
296 : {
297 56179 : if(BOOST_JSON_LIKELY(
298 : ! ec_ && more_))
299 : {
300 : // suspend
301 35861 : reserve();
302 35861 : st_.push_unchecked(n);
303 35861 : st_.push_unchecked(st);
304 : }
305 56179 : return sentinel();
306 : }
307 :
308 :
309 : template<class Handler>
310 : const char*
311 19074 : basic_parser<Handler>::
312 : fail(const char* p) noexcept
313 : {
314 19074 : BOOST_ASSERT( p != sentinel() );
315 19074 : end_ = p;
316 19074 : return sentinel();
317 : }
318 :
319 : template<class Handler>
320 : const char*
321 7781 : basic_parser<Handler>::
322 : fail(
323 : const char* p,
324 : error ev,
325 : source_location const* loc) noexcept
326 : {
327 7781 : BOOST_ASSERT( p != sentinel() );
328 7781 : end_ = p;
329 7781 : ec_.assign(ev, loc);
330 7781 : return sentinel();
331 : }
332 :
333 : template<class Handler>
334 : const char*
335 11323 : basic_parser<Handler>::
336 : maybe_suspend(
337 : const char* p,
338 : state st)
339 : {
340 11323 : if( p != sentinel() )
341 9445 : end_ = p;
342 11323 : if(BOOST_JSON_LIKELY(more_))
343 : {
344 : // suspend
345 11050 : reserve();
346 11050 : st_.push_unchecked(st);
347 : }
348 11323 : return sentinel();
349 : }
350 :
351 : template<class Handler>
352 : const char*
353 41250 : basic_parser<Handler>::
354 : maybe_suspend(
355 : const char* p,
356 : state st,
357 : std::size_t n)
358 : {
359 41250 : BOOST_ASSERT( p != sentinel() );
360 41250 : end_ = p;
361 41250 : if(BOOST_JSON_LIKELY(more_))
362 : {
363 : // suspend
364 40842 : reserve();
365 40842 : st_.push_unchecked(n);
366 40842 : st_.push_unchecked(st);
367 : }
368 41250 : return sentinel();
369 : }
370 :
371 : template<class Handler>
372 : const char*
373 1132 : basic_parser<Handler>::
374 : maybe_suspend(
375 : const char* p,
376 : state st,
377 : const number& num)
378 : {
379 1132 : BOOST_ASSERT( p != sentinel() );
380 1132 : end_ = p;
381 1132 : if(BOOST_JSON_LIKELY(more_))
382 : {
383 : // suspend
384 1132 : num_ = num;
385 1132 : reserve();
386 1132 : st_.push_unchecked(st);;
387 : }
388 1132 : return sentinel();
389 : }
390 :
391 : template<class Handler>
392 : const char*
393 88657 : basic_parser<Handler>::
394 : suspend(
395 : const char* p,
396 : state st)
397 : {
398 88657 : BOOST_ASSERT( p != sentinel() );
399 88657 : end_ = p;
400 : // suspend
401 88657 : reserve();
402 88657 : st_.push_unchecked(st);
403 88657 : return sentinel();
404 : }
405 :
406 : template<class Handler>
407 : const char*
408 8424890 : basic_parser<Handler>::
409 : suspend(
410 : const char* p,
411 : state st,
412 : const number& num)
413 : {
414 8424890 : BOOST_ASSERT( p != sentinel() );
415 8424890 : end_ = p;
416 : // suspend
417 8424890 : num_ = num;
418 8424890 : reserve();
419 8424890 : st_.push_unchecked(st);
420 8424890 : return sentinel();
421 : }
422 :
423 : template<class Handler>
424 : template<
425 : bool StackEmpty_/*,
426 : bool Terminal_*/>
427 : const char*
428 21764 : basic_parser<Handler>::
429 : parse_comment(const char* p,
430 : std::integral_constant<bool, StackEmpty_> stack_empty,
431 : /*std::integral_constant<bool, Terminal_>*/ bool terminal)
432 : {
433 21764 : detail::const_stream_wrapper cs(p, end_);
434 21764 : const char* start = cs.begin();
435 : std::size_t remain;
436 21764 : if(! stack_empty && ! st_.empty())
437 : {
438 : state st;
439 3515 : st_.pop(st);
440 3515 : switch(st)
441 : {
442 : default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
443 538 : case state::com1: goto do_com1;
444 2323 : case state::com2: goto do_com2;
445 438 : case state::com3: goto do_com3;
446 216 : case state::com4: goto do_com4;
447 : }
448 : }
449 18249 : BOOST_ASSERT(*cs == '/');
450 18249 : ++cs;
451 18787 : do_com1:
452 18787 : if(BOOST_JSON_UNLIKELY(! cs))
453 555 : return maybe_suspend(cs.begin(), state::com1);
454 18232 : switch(*cs)
455 : {
456 5 : default:
457 : {
458 : BOOST_STATIC_CONSTEXPR source_location loc
459 : = BOOST_CURRENT_LOCATION;
460 5 : return fail(cs.begin(), error::syntax, &loc);
461 : }
462 10543 : case '/':
463 10543 : ++cs;
464 12866 : do_com2:
465 : // KRYSTIAN TODO: this is a mess, we have to fix this
466 12866 : remain = cs.remain();
467 25732 : cs = remain ? static_cast<const char*>(
468 12866 : std::memchr(cs.begin(), '\n', remain)) : sentinel();
469 12866 : if(! cs.begin())
470 2143 : cs = sentinel();
471 12866 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
472 : {
473 : // if the doc does not terminate
474 : // with a newline, treat it as the
475 : // end of the comment
476 2574 : if(terminal && ! more_)
477 : {
478 39 : if(BOOST_JSON_UNLIKELY(! h_.on_comment(
479 : {start, cs.remain(start)}, ec_)))
480 2 : return fail(cs.end());
481 35 : return cs.end();
482 : }
483 2535 : if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
484 : {start, cs.remain(start)}, ec_)))
485 96 : return fail(cs.end());
486 2343 : if(terminal)
487 106 : return suspend(cs.end(), state::com2);
488 2237 : return maybe_suspend(cs.end(), state::com2);
489 : }
490 10292 : break;
491 1684 : case '*':
492 : do
493 : {
494 9368 : ++cs;
495 9806 : do_com3:
496 : // KRYSTIAN TODO: this is a mess, we have to fix this
497 9806 : remain = cs.remain();
498 19612 : cs = remain ? static_cast<const char*>(
499 9806 : std::memchr(cs.begin(), '*', remain)) : sentinel();
500 9806 : if(! cs.begin())
501 242 : cs = sentinel();
502 : // stopped inside a c comment
503 9806 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
504 : {
505 503 : if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
506 : {start, cs.remain(start)}, ec_)))
507 30 : return fail(cs.end());
508 443 : return maybe_suspend(cs.end(), state::com3);
509 : }
510 : // found a asterisk, check if the next char is a slash
511 9303 : ++cs;
512 9519 : do_com4:
513 9519 : if(BOOST_JSON_UNLIKELY(! cs))
514 : {
515 259 : if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
516 : {start, cs.used(start)}, ec_)))
517 18 : return fail(cs.begin());
518 223 : return maybe_suspend(cs.begin(), state::com4);
519 : }
520 : }
521 9260 : while(*cs != '/');
522 : }
523 17868 : ++cs;
524 17868 : if(BOOST_JSON_UNLIKELY(! h_.on_comment(
525 : {start, cs.used(start)}, ec_)))
526 968 : return fail(cs.begin());
527 15932 : return cs.begin();
528 : }
529 :
530 : template<class Handler>
531 : template<bool StackEmpty_>
532 : const char*
533 10710592 : basic_parser<Handler>::
534 : parse_document(const char* p,
535 : std::integral_constant<bool, StackEmpty_> stack_empty)
536 : {
537 10710592 : detail::const_stream_wrapper cs(p, end_);
538 10710592 : if(! stack_empty && ! st_.empty())
539 : {
540 : state st;
541 8561473 : st_.peek(st);
542 8561473 : switch(st)
543 : {
544 8475408 : default: goto do_doc2;
545 601 : case state::doc1:
546 601 : st_.pop(st);
547 601 : goto do_doc1;
548 85244 : case state::doc3:
549 85244 : st_.pop(st);
550 85244 : goto do_doc3;
551 220 : case state::com1: case state::com2:
552 : case state::com3: case state::com4:
553 220 : goto do_doc4;
554 : }
555 : }
556 2149119 : do_doc1:
557 2149720 : cs = detail::count_whitespace(cs.begin(), cs.end());
558 2149720 : if(BOOST_JSON_UNLIKELY(! cs))
559 633 : return maybe_suspend(cs.begin(), state::doc1);
560 2149087 : do_doc2:
561 10624495 : switch(+opt_.allow_comments |
562 10624495 : (opt_.allow_trailing_commas << 1) |
563 10624495 : (opt_.allow_invalid_utf8 << 2))
564 : {
565 : // no extensions
566 10600782 : default:
567 10600782 : cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::false_type(), std::false_type(), opt_.allow_invalid_utf16);
568 10585560 : break;
569 : // comments
570 13582 : case 1:
571 13582 : cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::false_type(), std::false_type(), opt_.allow_invalid_utf16);
572 11314 : break;
573 : // trailing
574 6710 : case 2:
575 6710 : cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::true_type(), std::false_type(), opt_.allow_invalid_utf16);
576 5117 : break;
577 : // comments & trailing
578 761 : case 3:
579 761 : cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::true_type(), std::false_type(), opt_.allow_invalid_utf16);
580 761 : break;
581 : // skip validation
582 760 : case 4:
583 760 : cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::false_type(), std::true_type(), opt_.allow_invalid_utf16);
584 760 : break;
585 : // comments & skip validation
586 760 : case 5:
587 760 : cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::false_type(), std::true_type(), opt_.allow_invalid_utf16);
588 760 : break;
589 : // trailing & skip validation
590 760 : case 6:
591 760 : cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::true_type(), std::true_type(), opt_.allow_invalid_utf16);
592 760 : break;
593 : // comments & trailing & skip validation
594 380 : case 7:
595 380 : cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::true_type(), std::true_type(), opt_.allow_invalid_utf16);
596 380 : break;
597 : }
598 10605412 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
599 : // the appropriate state has already been pushed into stack
600 8502706 : return sentinel();
601 2102706 : do_doc3:
602 2188282 : cs = detail::count_whitespace(cs.begin(), cs.end());
603 2188282 : if(BOOST_JSON_UNLIKELY(! cs))
604 : {
605 2185684 : if(more_)
606 88551 : return suspend(cs.begin(), state::doc3);
607 : }
608 2598 : else if(opt_.allow_comments && *cs == '/')
609 : {
610 536 : do_doc4:
611 756 : cs = parse_comment(cs.begin(), stack_empty, std::true_type());
612 671 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
613 339 : return sentinel();
614 332 : goto do_doc3;
615 : }
616 2099195 : return cs.begin();
617 : }
618 :
619 : template<class Handler>
620 : template<
621 : bool StackEmpty_,
622 : bool AllowComments_/*,
623 : bool AllowTrailing_,
624 : bool AllowBadUTF8_*/>
625 : const char*
626 10742129 : basic_parser<Handler>::
627 : parse_value(const char* p,
628 : std::integral_constant<bool, StackEmpty_> stack_empty,
629 : std::integral_constant<bool, AllowComments_> allow_comments,
630 : /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
631 : /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
632 : bool allow_bad_utf16)
633 : {
634 10742129 : if(stack_empty || st_.empty())
635 : {
636 2248335 : loop:
637 2253251 : switch(*p)
638 : {
639 22761 : case '0':
640 22761 : return mp11::mp_with_index<3>(
641 22761 : static_cast<unsigned char>(opt_.numbers),
642 22100 : parse_number_helper<true, '0'>{ this, p });
643 25185 : case '-':
644 25185 : return mp11::mp_with_index<3>(
645 25185 : static_cast<unsigned char>(opt_.numbers),
646 24073 : parse_number_helper<true, '-'>{ this, p });
647 2042025 : case '1': case '2': case '3':
648 : case '4': case '5': case '6':
649 : case '7': case '8': case '9':
650 2042025 : return mp11::mp_with_index<3>(
651 2042025 : static_cast<unsigned char>(opt_.numbers),
652 2039149 : parse_number_helper<true, '+'>{ this, p });
653 11381 : case 'n':
654 11381 : return parse_literal( p, detail::literals_c<detail::literals::null>() );
655 664 : case 't':
656 664 : return parse_literal( p, detail::literals_c<detail::literals::true_>() );
657 722 : case 'f':
658 722 : return parse_literal( p, detail::literals_c<detail::literals::false_>() );
659 681 : case 'I':
660 681 : if( !opt_.allow_infinity_and_nan )
661 : {
662 : BOOST_STATIC_CONSTEXPR source_location loc
663 : = BOOST_CURRENT_LOCATION;
664 24 : return fail(p, error::syntax, &loc);
665 : }
666 657 : return parse_literal( p, detail::literals_c<detail::literals::infinity>() );
667 231 : case 'N':
668 231 : if( !opt_.allow_infinity_and_nan )
669 : {
670 : BOOST_STATIC_CONSTEXPR source_location loc
671 : = BOOST_CURRENT_LOCATION;
672 30 : return fail(p, error::syntax, &loc);
673 : }
674 201 : return parse_literal(p, detail::literals_c<detail::literals::nan>() );
675 47587 : case '"':
676 47587 : return parse_string(p, std::true_type(), std::false_type(), allow_bad_utf8, allow_bad_utf16);
677 20618 : case '[':
678 20618 : return parse_array(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
679 74131 : case '{':
680 74131 : return parse_object(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
681 6144 : case '/':
682 6144 : if(! allow_comments)
683 : {
684 : BOOST_STATIC_CONSTEXPR source_location loc
685 : = BOOST_CURRENT_LOCATION;
686 284 : return fail(p, error::syntax, &loc);
687 : }
688 5860 : p = parse_comment(p, stack_empty, std::false_type());
689 : // KRYSTIAN NOTE: incomplete takes const_stream, we either
690 : // can add an overload, change the existing one to take a pointer,
691 : // or just leave it as is
692 5621 : if(BOOST_JSON_UNLIKELY(p == sentinel()))
693 602 : return maybe_suspend(p, state::val2);
694 : BOOST_FALLTHROUGH;
695 : case ' ':
696 : case '\t':
697 : case '\n':
698 : case '\r':
699 5035 : p = detail::count_whitespace(p, end_);
700 5035 : if(BOOST_JSON_UNLIKELY(p == end_))
701 119 : return maybe_suspend(p, state::val1);
702 4916 : goto loop;
703 1105 : default:
704 : {
705 : BOOST_STATIC_CONSTEXPR source_location loc
706 : = BOOST_CURRENT_LOCATION;
707 1105 : return fail(p, error::syntax, &loc);
708 : }
709 : }
710 : }
711 8493794 : return resume_value(p, allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
712 : }
713 :
714 : template<class Handler>
715 : template<
716 : bool AllowComments_/*,
717 : bool AllowTrailing_,
718 : bool AllowBadUTF8_*/>
719 : const char*
720 8493794 : basic_parser<Handler>::
721 : resume_value(const char* p,
722 : std::integral_constant<bool, AllowComments_> allow_comments,
723 : /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
724 : /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
725 : bool allow_bad_utf16)
726 : {
727 : state st;
728 8493794 : st_.peek(st);
729 8493794 : switch(st)
730 : {
731 : default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
732 1924 : case state::lit1:
733 1924 : return parse_literal(p, detail::literals_c<detail::literals::resume>() );
734 :
735 23268 : case state::str1: case state::str2:
736 : case state::str8:
737 23268 : return parse_string(p, std::false_type(), std::false_type(), allow_bad_utf8, allow_bad_utf16);
738 :
739 5730 : case state::arr1: case state::arr2:
740 : case state::arr3: case state::arr4:
741 : case state::arr5: case state::arr6:
742 5730 : return parse_array(p, std::false_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
743 :
744 35058 : case state::obj1: case state::obj2:
745 : case state::obj3: case state::obj4:
746 : case state::obj5: case state::obj6:
747 : case state::obj7: case state::obj8:
748 : case state::obj9: case state::obj10:
749 : case state::obj11:
750 35058 : return parse_object(p, std::false_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
751 :
752 8426019 : case state::num1: case state::num2:
753 : case state::num3: case state::num4:
754 : case state::num5: case state::num6:
755 : case state::num7: case state::num8:
756 : case state::exp1: case state::exp2:
757 : case state::exp3:
758 8426019 : return mp11::mp_with_index<3>(
759 8426019 : static_cast<unsigned char>(opt_.numbers),
760 8425164 : parse_number_helper<false, 0>{ this, p });
761 :
762 : // KRYSTIAN NOTE: these are special cases
763 112 : case state::val1:
764 : {
765 112 : st_.pop(st);
766 112 : BOOST_ASSERT(st_.empty());
767 112 : p = detail::count_whitespace(p, end_);
768 112 : if(BOOST_JSON_UNLIKELY(p == end_))
769 4 : return maybe_suspend(p, state::val1);
770 108 : return parse_value(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
771 : }
772 :
773 1616 : case state::val2:
774 : {
775 1616 : st_.pop(st);
776 1616 : p = parse_comment(p, std::false_type(), std::false_type());
777 1596 : if(BOOST_JSON_UNLIKELY(p == sentinel()))
778 1276 : return maybe_suspend(p, state::val2);
779 320 : if(BOOST_JSON_UNLIKELY( p == end_ ))
780 77 : return maybe_suspend(p, state::val3);
781 243 : BOOST_ASSERT(st_.empty());
782 243 : return parse_value(p, std::true_type(), std::true_type(), allow_trailing, allow_bad_utf8, allow_bad_utf16);
783 : }
784 :
785 67 : case state::val3:
786 : {
787 67 : st_.pop(st);
788 67 : return parse_value(p, std::true_type(), std::true_type(), allow_trailing, allow_bad_utf8, allow_bad_utf16);
789 : }
790 : }
791 : }
792 :
793 : template<class Handler>
794 : template<class Literal>
795 : const char*
796 16565 : basic_parser<Handler>::
797 : parse_literal(const char* p, Literal)
798 : {
799 : using L = detail::literals;
800 :
801 : std::size_t cur_lit;
802 : std::size_t offset;
803 :
804 16565 : detail::const_stream_wrapper cs(p, end_);
805 : BOOST_IF_CONSTEXPR( Literal::value != L::resume )
806 : {
807 13634 : constexpr std::size_t index = literal_index(Literal::value);
808 13634 : constexpr char const* literal = detail::literal_strings[index];
809 13634 : constexpr std::size_t sz = detail::literal_sizes[index];
810 :
811 13634 : if(BOOST_JSON_LIKELY( cs.remain() >= sz ))
812 : {
813 11984 : int const cmp = std::memcmp(cs.begin(), literal, sz);
814 11984 : if( cmp != 0 )
815 : {
816 : BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
817 197 : return fail(cs.begin(), error::syntax, &loc);
818 : }
819 :
820 : BOOST_IF_CONSTEXPR( Literal::value == L::null )
821 : {
822 10789 : if(BOOST_JSON_UNLIKELY(
823 : ! h_.on_null(ec_)))
824 161 : return fail(cs.begin());
825 : }
826 : else BOOST_IF_CONSTEXPR( Literal::value == L::true_ )
827 : {
828 384 : if(BOOST_JSON_UNLIKELY(
829 : ! h_.on_bool(true, ec_)))
830 14 : return fail(cs.begin());
831 : }
832 : else BOOST_IF_CONSTEXPR( Literal::value == L::false_ )
833 : {
834 406 : if(BOOST_JSON_UNLIKELY(
835 : ! h_.on_bool(false, ec_)))
836 13 : return fail(cs.begin());
837 : }
838 : else BOOST_IF_CONSTEXPR( Literal::value == L::infinity )
839 : {
840 103 : if(BOOST_JSON_UNLIKELY(
841 : ! h_.on_double(
842 : std::numeric_limits<double>::infinity(),
843 : string_view(literal, sz),
844 : ec_)))
845 13 : return fail(cs.begin());
846 : }
847 : else BOOST_IF_CONSTEXPR( Literal::value == L::neg_infinity )
848 : {
849 9 : if(BOOST_JSON_UNLIKELY(
850 : ! h_.on_double(
851 : -std::numeric_limits<double>::infinity(),
852 : string_view(literal, sz),
853 : ec_)))
854 1 : return fail(cs.begin());
855 : }
856 : else BOOST_IF_CONSTEXPR( Literal::value == L::nan )
857 : {
858 96 : if(BOOST_JSON_UNLIKELY(
859 : ! h_.on_double(
860 : std::numeric_limits<double>::quiet_NaN(),
861 : string_view(literal, sz),
862 : ec_)))
863 12 : return fail(cs.begin());
864 : }
865 : else
866 : {
867 : BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
868 : }
869 :
870 11363 : cs += sz;
871 11363 : return cs.begin();
872 : }
873 :
874 1650 : offset = 0;
875 1650 : cur_lit = index;
876 : }
877 : else
878 : {
879 : state st;
880 2931 : st_.pop(st);
881 2931 : BOOST_ASSERT( st == state::lit1 );
882 :
883 2931 : cur_lit = cur_lit_;
884 2931 : offset = lit_offset_;
885 : }
886 :
887 4581 : std::size_t const lit_size = detail::literal_sizes[cur_lit];
888 4581 : std::size_t const size = (std::min)( lit_size - offset, cs.remain() );
889 4581 : int cmp = 0;
890 4581 : if(BOOST_JSON_LIKELY( cs.begin() ))
891 4580 : cmp = std::memcmp(
892 4580 : cs.begin(), detail::literal_strings[cur_lit] + offset, size );
893 4581 : if( cmp != 0 )
894 : {
895 : BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
896 699 : return fail(cs.begin(), error::syntax, &loc);
897 : }
898 :
899 3882 : if(BOOST_JSON_UNLIKELY( offset + size < lit_size ))
900 : {
901 1990 : BOOST_ASSERT( cur_lit < 256 );
902 1990 : cur_lit_ = static_cast<unsigned char>( cur_lit );
903 1990 : BOOST_ASSERT( offset + size < 256 );
904 1990 : lit_offset_ = static_cast<unsigned char>( offset + size );
905 1990 : return maybe_suspend(cs.begin() + size, state::lit1);
906 : }
907 :
908 1892 : switch( static_cast<L>(cur_lit) )
909 : {
910 472 : case L::null:
911 472 : if(BOOST_JSON_UNLIKELY(
912 : ! h_.on_null(ec_)))
913 61 : return fail(cs.begin());
914 351 : break;
915 152 : case L::true_:
916 152 : if(BOOST_JSON_UNLIKELY(
917 : ! h_.on_bool(true, ec_)))
918 22 : return fail(cs.begin());
919 109 : break;
920 198 : case L::false_:
921 198 : if(BOOST_JSON_UNLIKELY(
922 : ! h_.on_bool(false, ec_)))
923 28 : return fail(cs.begin());
924 142 : break;
925 308 : case L::infinity:
926 308 : if(BOOST_JSON_UNLIKELY(
927 : ! h_.on_double(
928 : std::numeric_limits<double>::infinity(),
929 : string_view(
930 : detail::literal_strings[ literal_index(L::infinity) ],
931 : detail::literal_sizes[ literal_index(L::infinity) ]),
932 : ec_)))
933 49 : return fail(cs.begin());
934 210 : break;
935 686 : case L::neg_infinity:
936 686 : if(BOOST_JSON_UNLIKELY(
937 : ! h_.on_double(
938 : -std::numeric_limits<double>::infinity(),
939 : string_view(
940 : detail::literal_strings[ literal_index(L::neg_infinity) ],
941 : detail::literal_sizes[ literal_index(L::neg_infinity) ]),
942 : ec_)))
943 102 : return fail(cs.begin());
944 482 : break;
945 76 : case L::nan:
946 76 : if(BOOST_JSON_UNLIKELY(
947 : ! h_.on_double(
948 : std::numeric_limits<double>::quiet_NaN(),
949 : string_view(
950 : detail::literal_strings[ literal_index(L::nan) ],
951 : detail::literal_sizes[ literal_index(L::nan) ]),
952 : ec_)))
953 12 : return fail(cs.begin());
954 52 : break;
955 : default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
956 : }
957 :
958 1346 : cs += size;
959 1346 : return cs.begin();
960 : }
961 :
962 : //----------------------------------------------------------
963 :
964 : template<class Handler>
965 : template<bool StackEmpty_, bool IsKey_>
966 : const char*
967 164330 : basic_parser<Handler>::
968 : parse_string(const char* p,
969 : std::integral_constant<bool, StackEmpty_> stack_empty,
970 : std::integral_constant<bool, IsKey_> is_key,
971 : bool allow_bad_utf8,
972 : bool allow_bad_utf16)
973 : {
974 164330 : detail::const_stream_wrapper cs(p, end_);
975 : std::size_t total;
976 : char const* start;
977 : std::size_t size;
978 164330 : if(! stack_empty && ! st_.empty())
979 : {
980 : state st;
981 35915 : st_.pop(st);
982 35915 : st_.pop(total);
983 35915 : switch(st)
984 : {
985 : default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
986 3149 : case state::str2: goto do_str2;
987 1868 : case state::str8: goto do_str8;
988 30898 : case state::str1: break;
989 : }
990 : }
991 : else
992 : {
993 128415 : BOOST_ASSERT(*cs == '\x22'); // '"'
994 128415 : ++cs;
995 128415 : total = 0;
996 : }
997 :
998 167806 : do_str1:
999 167806 : start = cs.begin();
1000 335612 : cs = allow_bad_utf8?
1001 2177 : detail::count_valid<true>(cs.begin(), cs.end()):
1002 165629 : detail::count_valid<false>(cs.begin(), cs.end());
1003 167806 : size = cs.used(start);
1004 167806 : if(is_key)
1005 : {
1006 46694 : BOOST_ASSERT(total <= Handler::max_key_size);
1007 94005 : if(BOOST_JSON_UNLIKELY(size >
1008 : Handler::max_key_size - total))
1009 : {
1010 : BOOST_STATIC_CONSTEXPR source_location loc
1011 : = BOOST_CURRENT_LOCATION;
1012 3 : return fail(cs.begin(), error::key_too_large, &loc);
1013 : }
1014 : }
1015 : else
1016 : {
1017 38330 : BOOST_ASSERT(total <= Handler::max_string_size);
1018 73801 : if(BOOST_JSON_UNLIKELY(size >
1019 : Handler::max_string_size - total))
1020 : {
1021 : BOOST_STATIC_CONSTEXPR source_location loc
1022 : = BOOST_CURRENT_LOCATION;
1023 3 : return fail(cs.begin(), error::string_too_large, &loc);
1024 : }
1025 : }
1026 167800 : total += size;
1027 167800 : if(BOOST_JSON_UNLIKELY(! cs))
1028 : {
1029 : // call handler if the string isn't empty
1030 33232 : if(BOOST_JSON_LIKELY(size))
1031 : {
1032 : {
1033 30066 : bool r = is_key?
1034 12404 : h_.on_key_part( {start, size}, total, ec_ ):
1035 18996 : h_.on_string_part( {start, size}, total, ec_ );
1036 :
1037 28958 : if(BOOST_JSON_UNLIKELY(!r))
1038 : {
1039 1110 : return fail(cs.begin());
1040 : }
1041 : }
1042 : }
1043 31014 : return maybe_suspend(cs.begin(), state::str1, total);
1044 : }
1045 : // at this point all valid characters have been skipped, so any remaining
1046 : // if there are any more characters, they are either escaped, or incomplete
1047 : // utf8, or invalid utf8
1048 134568 : if(BOOST_JSON_UNLIKELY(*cs != '\x22')) // '"'
1049 : {
1050 : // sequence is invalid or incomplete
1051 15081 : if((*cs & 0x80) && !allow_bad_utf8)
1052 : {
1053 3472 : seq_.save(cs.begin(), cs.remain());
1054 3472 : if(BOOST_JSON_UNLIKELY(seq_.complete()))
1055 : {
1056 : BOOST_STATIC_CONSTEXPR source_location loc
1057 : = BOOST_CURRENT_LOCATION;
1058 1557 : return fail(cs.begin(), error::syntax, &loc);
1059 : }
1060 1915 : if(BOOST_JSON_LIKELY(size))
1061 : {
1062 245 : bool const r = is_key?
1063 22 : h_.on_key_part( {start, size}, total, ec_ ):
1064 245 : h_.on_string_part( {start, size}, total, ec_ );
1065 223 : if(BOOST_JSON_UNLIKELY( !r ))
1066 22 : return fail( cs.begin() );
1067 : }
1068 1871 : return maybe_suspend(cs.end(), state::str8, total);
1069 : }
1070 11609 : else if(BOOST_JSON_LIKELY(*cs == '\\'))
1071 : {
1072 : // flush unescaped run from input
1073 11500 : if(BOOST_JSON_LIKELY(size))
1074 : {
1075 4250 : bool const r = is_key?
1076 1226 : h_.on_key_part( {start, size}, total, ec_ ):
1077 3554 : h_.on_string_part( {start, size}, total, ec_ );
1078 3766 : if(BOOST_JSON_UNLIKELY( !r ))
1079 484 : return fail( cs.begin() );
1080 : }
1081 7250 : do_str2:
1082 13681 : cs = parse_escaped(cs.begin(), total, stack_empty, is_key, allow_bad_utf16);
1083 12719 : if(BOOST_JSON_UNLIKELY( incomplete(cs) ))
1084 5476 : return suspend_or_fail(state::str2, total);
1085 :
1086 7243 : goto do_str1;
1087 : }
1088 : // illegal control
1089 : BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1090 109 : return fail(cs.begin(), error::syntax, &loc);
1091 : }
1092 :
1093 : {
1094 119487 : bool r = is_key?
1095 84511 : h_.on_key( {start, size}, total, ec_ ):
1096 41985 : h_.on_string( {start, size}, total, ec_ );
1097 :
1098 115113 : if(BOOST_JSON_UNLIKELY(!r))
1099 : {
1100 4318 : return fail(cs.begin());
1101 : }
1102 : }
1103 :
1104 110795 : ++cs;
1105 110795 : return cs.begin();
1106 :
1107 1868 : do_str8:
1108 1868 : uint8_t needed = seq_.needed();
1109 1868 : if(BOOST_JSON_UNLIKELY( !seq_.append(cs.begin(), cs.remain()) ))
1110 4 : return maybe_suspend(cs.end(), state::str8, total);
1111 1864 : if(BOOST_JSON_UNLIKELY( !seq_.valid() ))
1112 : {
1113 : BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1114 210 : return fail(cs.begin(), error::syntax, &loc);
1115 : }
1116 : {
1117 1654 : std::size_t const n = seq_.length();
1118 : bool r;
1119 1654 : if(is_key)
1120 : {
1121 2 : BOOST_ASSERT(total <= Handler::max_key_size);
1122 2 : if(BOOST_JSON_UNLIKELY(n >
1123 : Handler::max_key_size - total))
1124 : {
1125 : BOOST_STATIC_CONSTEXPR source_location loc
1126 : = BOOST_CURRENT_LOCATION;
1127 1 : return fail(cs.begin(), error::key_too_large, &loc);
1128 : }
1129 1 : total += n;
1130 1 : r = h_.on_key_part( {seq_.data(), n}, total, ec_ );
1131 : }
1132 : else
1133 : {
1134 1 : BOOST_ASSERT(total <= Handler::max_string_size);
1135 1652 : if(BOOST_JSON_UNLIKELY(n >
1136 : Handler::max_string_size - total))
1137 : {
1138 : BOOST_STATIC_CONSTEXPR source_location loc
1139 : = BOOST_CURRENT_LOCATION;
1140 1 : return fail(cs.begin(), error::string_too_large, &loc);
1141 : }
1142 1651 : total += n;
1143 1651 : r = h_.on_string_part( {seq_.data(), n}, total, ec_ );
1144 : }
1145 1451 : if(BOOST_JSON_UNLIKELY( !r ))
1146 201 : return fail( cs.begin() );
1147 : }
1148 1250 : cs += needed;
1149 1250 : goto do_str1;
1150 : }
1151 :
1152 : template<class Handler>
1153 : template<bool StackEmpty_>
1154 : const char*
1155 13681 : basic_parser<Handler>::
1156 : parse_escaped(
1157 : const char* p,
1158 : std::size_t& total,
1159 : std::integral_constant<bool, StackEmpty_> stack_empty,
1160 : bool is_key,
1161 : bool allow_bad_utf16)
1162 : {
1163 13681 : constexpr unsigned urc = 0xFFFD; // Unicode replacement character
1164 13681 : auto const ev_too_large = is_key?
1165 : error::key_too_large : error::string_too_large;
1166 13681 : auto const max_size = is_key?
1167 : Handler::max_key_size : Handler::max_string_size;
1168 : int digit;
1169 :
1170 : //---------------------------------------------------------------
1171 : //
1172 : // To handle escapes, a local temporary buffer accumulates
1173 : // the unescaped result. The algorithm attempts to fill the
1174 : // buffer to capacity before invoking the handler.
1175 : // In some cases the temporary buffer needs to be flushed
1176 : // before it is full:
1177 : // * When the closing double quote is seen
1178 : // * When there in no more input (and more is expected later)
1179 : // A goal of the algorithm is to call the handler as few times
1180 : // as possible. Thus, when the first escape is encountered,
1181 : // the algorithm attempts to fill the temporary buffer first.
1182 : //
1183 13681 : detail::buffer<BOOST_JSON_STACK_BUFFER_SIZE> temp;
1184 :
1185 : // Unescaped JSON is never larger than its escaped version.
1186 : // To efficiently process only what will fit in the temporary buffer,
1187 : // the size of the input stream is temporarily "clipped" to the size
1188 : // of the temporary buffer.
1189 : // handle escaped character
1190 13681 : detail::clipped_const_stream cs(p, end_);
1191 13681 : cs.clip(temp.max_size());
1192 :
1193 13681 : if(! stack_empty && ! st_.empty())
1194 : {
1195 : state st;
1196 3149 : st_.pop(st);
1197 3149 : switch(st)
1198 : {
1199 : default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
1200 528 : case state::str3: goto do_str3;
1201 392 : case state::str4: goto do_str4;
1202 390 : case state::str5: goto do_str5;
1203 389 : case state::str6: goto do_str6;
1204 386 : case state::str7: goto do_str7;
1205 232 : case state::sur1: goto do_sur1;
1206 188 : case state::sur2: goto do_sur2;
1207 164 : case state::sur3: goto do_sur3;
1208 162 : case state::sur4: goto do_sur4;
1209 160 : case state::sur5: goto do_sur5;
1210 158 : case state::sur6: goto do_sur6;
1211 : }
1212 : }
1213 :
1214 3783 : while(true)
1215 : {
1216 14315 : BOOST_ASSERT( temp.capacity() );
1217 14315 : BOOST_ASSERT(*cs == '\\');
1218 14315 : ++cs;
1219 15174 : do_str3:
1220 15379 : if(BOOST_JSON_UNLIKELY(! cs))
1221 : {
1222 562 : if(BOOST_JSON_LIKELY(! temp.empty()))
1223 : {
1224 1 : BOOST_ASSERT(total <= max_size);
1225 101 : if(BOOST_JSON_UNLIKELY(
1226 : temp.size() > max_size - total))
1227 : {
1228 : BOOST_STATIC_CONSTEXPR source_location loc
1229 : = BOOST_CURRENT_LOCATION;
1230 1 : return fail(cs.begin(), ev_too_large, &loc);
1231 : }
1232 100 : total += temp.size();
1233 : {
1234 91 : bool r = is_key
1235 100 : ? h_.on_key_part(temp.get(), total, ec_)
1236 100 : : h_.on_string_part(temp.get(), total, ec_);
1237 :
1238 91 : if(BOOST_JSON_UNLIKELY(!r))
1239 : {
1240 9 : return fail(cs.begin());
1241 : }
1242 : }
1243 82 : temp.clear();
1244 : }
1245 543 : cs.clip(temp.max_size());
1246 543 : if(BOOST_JSON_UNLIKELY(! cs))
1247 543 : return maybe_suspend(cs.begin(), state::str3);
1248 : }
1249 14817 : switch(*cs)
1250 : {
1251 191 : default:
1252 : {
1253 : BOOST_STATIC_CONSTEXPR source_location loc
1254 : = BOOST_CURRENT_LOCATION;
1255 191 : return fail(cs.begin(), error::syntax, &loc);
1256 : }
1257 265 : case '\x22': // '"'
1258 265 : temp.push_back('\x22');
1259 265 : ++cs;
1260 265 : break;
1261 178 : case '\\':
1262 178 : temp.push_back('\\');
1263 178 : ++cs;
1264 178 : break;
1265 96 : case '/':
1266 96 : temp.push_back('/');
1267 96 : ++cs;
1268 96 : break;
1269 112 : case 'b':
1270 112 : temp.push_back('\x08');
1271 112 : ++cs;
1272 112 : break;
1273 108 : case 'f':
1274 108 : temp.push_back('\x0c');
1275 108 : ++cs;
1276 108 : break;
1277 1766 : case 'n':
1278 1766 : temp.push_back('\x0a');
1279 1766 : ++cs;
1280 1766 : break;
1281 146 : case 'r':
1282 146 : temp.push_back('\x0d');
1283 146 : ++cs;
1284 146 : break;
1285 266 : case 't':
1286 266 : temp.push_back('\x09');
1287 266 : ++cs;
1288 266 : break;
1289 11689 : case 'u':
1290 : // utf16 escape
1291 : //
1292 : // fast path only when the buffer
1293 : // is large enough for 2 surrogates
1294 11689 : if(BOOST_JSON_LIKELY(cs.remain() > 10))
1295 : {
1296 : // KRYSTIAN TODO: this could be done
1297 : // with fewer instructions
1298 11394 : digit = detail::load_little_endian<4>(
1299 5697 : cs.begin() + 1);
1300 5697 : int d4 = detail::hex_digit(static_cast<
1301 5697 : unsigned char>(digit >> 24));
1302 5697 : int d3 = detail::hex_digit(static_cast<
1303 5697 : unsigned char>(digit >> 16));
1304 5697 : int d2 = detail::hex_digit(static_cast<
1305 5697 : unsigned char>(digit >> 8));
1306 5697 : int d1 = detail::hex_digit(static_cast<
1307 : unsigned char>(digit));
1308 5697 : if(BOOST_JSON_UNLIKELY(
1309 : (d1 | d2 | d3 | d4) == -1))
1310 : {
1311 60 : if(d1 != -1)
1312 45 : ++cs;
1313 60 : if(d2 != -1)
1314 30 : ++cs;
1315 60 : if(d3 != -1)
1316 15 : ++cs;
1317 : BOOST_STATIC_CONSTEXPR source_location loc
1318 : = BOOST_CURRENT_LOCATION;
1319 60 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1320 : }
1321 : // 32 bit unicode scalar value
1322 5637 : unsigned u1 =
1323 5637 : (d1 << 12) + (d2 << 8) +
1324 5637 : (d3 << 4) + d4;
1325 : // valid unicode scalar values are
1326 : // [0, D7FF] and [E000, 10FFFF]
1327 : // values within this range are valid utf-8
1328 : // code points and invalid leading surrogates.
1329 5637 : if(BOOST_JSON_LIKELY(
1330 : u1 < 0xd800 || u1 > 0xdfff))
1331 : {
1332 1340 : cs += 5;
1333 1340 : temp.append_utf8(u1);
1334 1340 : break;
1335 : }
1336 4297 : if(BOOST_JSON_UNLIKELY(u1 > 0xdbff))
1337 : {
1338 : // If it's an illegal leading surrogate and
1339 : // the parser does not allow it, return an error.
1340 707 : if(!allow_bad_utf16)
1341 : {
1342 : BOOST_STATIC_CONSTEXPR source_location loc
1343 : = BOOST_CURRENT_LOCATION;
1344 122 : return fail(cs.begin(), error::illegal_leading_surrogate,
1345 122 : &loc);
1346 : }
1347 : // Otherwise, append the Unicode replacement character
1348 : else
1349 : {
1350 585 : cs += 5;
1351 585 : temp.append_utf8(urc);
1352 585 : break;
1353 : }
1354 : }
1355 3590 : cs += 5;
1356 : // KRYSTIAN TODO: this can be a two byte load
1357 : // and a single comparison. We lose error information,
1358 : // but it's faster.
1359 3590 : if(BOOST_JSON_UNLIKELY(*cs != '\\'))
1360 : {
1361 : // If the next character is not a backslash and
1362 : // the parser does not allow it, return a syntax error.
1363 156 : if(!allow_bad_utf16)
1364 : {
1365 : BOOST_STATIC_CONSTEXPR source_location loc
1366 : = BOOST_CURRENT_LOCATION;
1367 15 : return fail(cs.begin(), error::syntax, &loc);
1368 : }
1369 : // Otherwise, append the Unicode replacement character since
1370 : // the first code point is a valid leading surrogate
1371 : else
1372 : {
1373 141 : temp.append_utf8(urc);
1374 141 : break;
1375 : }
1376 : }
1377 3434 : ++cs;
1378 3434 : if(BOOST_JSON_UNLIKELY(*cs != 'u'))
1379 : {
1380 220 : if (!allow_bad_utf16)
1381 : {
1382 : BOOST_STATIC_CONSTEXPR source_location loc
1383 : = BOOST_CURRENT_LOCATION;
1384 15 : return fail(cs.begin(), error::syntax, &loc);
1385 : }
1386 : // Otherwise, append the Unicode replacement character since
1387 : // the first code point is a valid leading surrogate
1388 : else
1389 : {
1390 205 : temp.append_utf8(urc);
1391 205 : goto do_str3;
1392 : }
1393 : }
1394 3214 : ++cs;
1395 3214 : digit = detail::load_little_endian<4>(cs.begin());
1396 3214 : d4 = detail::hex_digit(static_cast<
1397 3214 : unsigned char>(digit >> 24));
1398 3214 : d3 = detail::hex_digit(static_cast<
1399 3214 : unsigned char>(digit >> 16));
1400 3214 : d2 = detail::hex_digit(static_cast<
1401 3214 : unsigned char>(digit >> 8));
1402 3214 : d1 = detail::hex_digit(static_cast<
1403 : unsigned char>(digit));
1404 3214 : if(BOOST_JSON_UNLIKELY(
1405 : (d1 | d2 | d3 | d4) == -1))
1406 : {
1407 90 : if(d1 != -1)
1408 75 : ++cs;
1409 90 : if(d2 != -1)
1410 45 : ++cs;
1411 90 : if(d3 != -1)
1412 15 : ++cs;
1413 : BOOST_STATIC_CONSTEXPR source_location loc
1414 : = BOOST_CURRENT_LOCATION;
1415 90 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1416 : }
1417 3124 : unsigned u2 =
1418 3124 : (d1 << 12) + (d2 << 8) +
1419 3124 : (d3 << 4) + d4;
1420 : // Check if the second code point is a valid trailing surrogate.
1421 : // Valid trailing surrogates are [DC00, DFFF]
1422 3124 : if(BOOST_JSON_UNLIKELY(
1423 : u2 < 0xdc00 || u2 > 0xdfff))
1424 : {
1425 : // If not valid and the parser does not allow it, return an error.
1426 1353 : if(!allow_bad_utf16)
1427 : {
1428 : BOOST_STATIC_CONSTEXPR source_location loc
1429 : = BOOST_CURRENT_LOCATION;
1430 136 : return fail(cs.begin(), error::illegal_trailing_surrogate,
1431 136 : &loc);
1432 : }
1433 : // Append the replacement character for the
1434 : // first leading surrogate.
1435 1217 : cs += 4;
1436 1217 : temp.append_utf8(urc);
1437 : // Check if the second code point is a
1438 : // valid unicode scalar value (invalid leading
1439 : // or trailing surrogate)
1440 1217 : if (u2 < 0xd800 || u2 > 0xdbff)
1441 : {
1442 524 : temp.append_utf8(u2);
1443 524 : break;
1444 : }
1445 : // If it is a valid leading surrogate
1446 : else
1447 : {
1448 693 : u1_ = u2;
1449 693 : goto do_sur1;
1450 : }
1451 : }
1452 1771 : cs += 4;
1453 : // Calculate the Unicode code point from the surrogate pair and
1454 : // append the UTF-8 representation.
1455 1771 : unsigned cp =
1456 1771 : ((u1 - 0xd800) << 10) +
1457 : ((u2 - 0xdc00)) +
1458 : 0x10000;
1459 : // utf-16 surrogate pair
1460 1771 : temp.append_utf8(cp);
1461 1771 : break;
1462 : }
1463 : // flush
1464 5992 : if(BOOST_JSON_LIKELY(! temp.empty()))
1465 : {
1466 4 : BOOST_ASSERT(total <= max_size);
1467 1723 : if(BOOST_JSON_UNLIKELY(
1468 : temp.size() > max_size - total))
1469 : {
1470 : BOOST_STATIC_CONSTEXPR source_location loc
1471 : = BOOST_CURRENT_LOCATION;
1472 1 : return fail(cs.begin(), ev_too_large, &loc);
1473 : }
1474 1722 : total += temp.size();
1475 : {
1476 1582 : bool r = is_key
1477 1722 : ? h_.on_key_part(temp.get(), total, ec_)
1478 1722 : : h_.on_string_part(temp.get(), total, ec_);
1479 :
1480 1582 : if(BOOST_JSON_UNLIKELY(!r))
1481 : {
1482 140 : return fail(cs.begin());
1483 : }
1484 : }
1485 1442 : temp.clear();
1486 1442 : cs.clip(temp.max_size());
1487 : }
1488 5711 : ++cs;
1489 : // utf-16 escape
1490 6103 : do_str4:
1491 6103 : if(BOOST_JSON_UNLIKELY(! cs))
1492 392 : return maybe_suspend(cs.begin(), state::str4);
1493 5711 : digit = detail::hex_digit(*cs);
1494 5711 : if(BOOST_JSON_UNLIKELY(digit == -1))
1495 : {
1496 : BOOST_STATIC_CONSTEXPR source_location loc
1497 : = BOOST_CURRENT_LOCATION;
1498 50 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1499 : }
1500 5661 : ++cs;
1501 5661 : u1_ = digit << 12;
1502 6051 : do_str5:
1503 6051 : if(BOOST_JSON_UNLIKELY(! cs))
1504 390 : return maybe_suspend(cs.begin(), state::str5);
1505 5661 : digit = detail::hex_digit(*cs);
1506 5661 : if(BOOST_JSON_UNLIKELY(digit == -1))
1507 : {
1508 : BOOST_STATIC_CONSTEXPR source_location loc
1509 : = BOOST_CURRENT_LOCATION;
1510 20 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1511 : }
1512 5641 : ++cs;
1513 5641 : u1_ += digit << 8;
1514 6030 : do_str6:
1515 6030 : if(BOOST_JSON_UNLIKELY(! cs))
1516 389 : return maybe_suspend(cs.begin(), state::str6);
1517 5641 : digit = detail::hex_digit(*cs);
1518 5641 : if(BOOST_JSON_UNLIKELY(digit == -1))
1519 : {
1520 : BOOST_STATIC_CONSTEXPR source_location loc
1521 : = BOOST_CURRENT_LOCATION;
1522 20 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1523 : }
1524 5621 : ++cs;
1525 5621 : u1_ += digit << 4;
1526 6007 : do_str7:
1527 6007 : if(BOOST_JSON_UNLIKELY(! cs))
1528 386 : return maybe_suspend(cs.begin(), state::str7);
1529 5621 : digit = detail::hex_digit(*cs);
1530 5621 : if(BOOST_JSON_UNLIKELY(digit == -1))
1531 : {
1532 : BOOST_STATIC_CONSTEXPR source_location loc
1533 : = BOOST_CURRENT_LOCATION;
1534 35 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1535 : }
1536 5586 : ++cs;
1537 5586 : u1_ += digit;
1538 5586 : if(BOOST_JSON_LIKELY(
1539 : u1_ < 0xd800 || u1_ > 0xdfff))
1540 : {
1541 1434 : BOOST_ASSERT(temp.empty());
1542 : // utf-8 codepoint
1543 1434 : temp.append_utf8(u1_);
1544 1434 : break;
1545 : }
1546 4152 : if(BOOST_JSON_UNLIKELY(u1_ > 0xdbff))
1547 : {
1548 : // If it's an illegal leading surrogate and
1549 : // the parser does not allow it, return an error.
1550 1585 : if(!allow_bad_utf16)
1551 : {
1552 : BOOST_STATIC_CONSTEXPR source_location loc
1553 : = BOOST_CURRENT_LOCATION;
1554 209 : return fail(cs.begin(), error::illegal_leading_surrogate, &loc);
1555 : }
1556 : // Otherwise, append the Unicode replacement character
1557 : else
1558 : {
1559 1376 : BOOST_ASSERT(temp.empty());
1560 1376 : temp.append_utf8(urc);
1561 1376 : break;
1562 : }
1563 : }
1564 2567 : do_sur1:
1565 3792 : if(BOOST_JSON_UNLIKELY(! cs))
1566 232 : return maybe_suspend(cs.begin(), state::sur1);
1567 3560 : if(BOOST_JSON_UNLIKELY(*cs != '\\'))
1568 : {
1569 : // If the next character is not a backslash and
1570 : // the parser does not allow it, return a syntax error.
1571 952 : if(!allow_bad_utf16)
1572 : {
1573 : BOOST_STATIC_CONSTEXPR source_location loc
1574 : = BOOST_CURRENT_LOCATION;
1575 149 : return fail(cs.begin(), error::syntax, &loc);
1576 : }
1577 : // Otherwise, append the Unicode replacement character since
1578 : // the first code point is a valid leading surrogate
1579 : else
1580 : {
1581 803 : temp.append_utf8(urc);
1582 803 : break;
1583 : }
1584 : }
1585 2608 : ++cs;
1586 2796 : do_sur2:
1587 2796 : if(BOOST_JSON_UNLIKELY(! cs))
1588 188 : return maybe_suspend(cs.begin(), state::sur2);
1589 2608 : if(BOOST_JSON_UNLIKELY(*cs != 'u'))
1590 : {
1591 396 : if (!allow_bad_utf16)
1592 : {
1593 : BOOST_STATIC_CONSTEXPR source_location loc
1594 : = BOOST_CURRENT_LOCATION;
1595 65 : return fail(cs.begin(), error::syntax, &loc);
1596 : }
1597 : // Otherwise, append the Unicode replacement character since
1598 : // the first code point is a valid leading surrogate
1599 : else
1600 : {
1601 331 : temp.append_utf8(urc);
1602 331 : goto do_str3;
1603 : }
1604 : }
1605 2212 : ++cs;
1606 2376 : do_sur3:
1607 2376 : if(BOOST_JSON_UNLIKELY(! cs))
1608 164 : return maybe_suspend(cs.begin(), state::sur3);
1609 2212 : digit = detail::hex_digit(*cs);
1610 2212 : if(BOOST_JSON_UNLIKELY(digit == -1))
1611 : {
1612 : BOOST_STATIC_CONSTEXPR source_location loc
1613 : = BOOST_CURRENT_LOCATION;
1614 35 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1615 : }
1616 2177 : ++cs;
1617 2177 : u2_ = digit << 12;
1618 2339 : do_sur4:
1619 2339 : if(BOOST_JSON_UNLIKELY(! cs))
1620 162 : return maybe_suspend(cs.begin(), state::sur4);
1621 2177 : digit = detail::hex_digit(*cs);
1622 2177 : if(BOOST_JSON_UNLIKELY(digit == -1))
1623 : {
1624 : BOOST_STATIC_CONSTEXPR source_location loc
1625 : = BOOST_CURRENT_LOCATION;
1626 35 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1627 : }
1628 2142 : ++cs;
1629 2142 : u2_ += digit << 8;
1630 2302 : do_sur5:
1631 2302 : if(BOOST_JSON_UNLIKELY(! cs))
1632 160 : return maybe_suspend(cs.begin(), state::sur5);
1633 2142 : digit = detail::hex_digit(*cs);
1634 2142 : if(BOOST_JSON_UNLIKELY(digit == -1))
1635 : {
1636 : BOOST_STATIC_CONSTEXPR source_location loc
1637 : = BOOST_CURRENT_LOCATION;
1638 20 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1639 : }
1640 2122 : ++cs;
1641 2122 : u2_ += digit << 4;
1642 2280 : do_sur6:
1643 2280 : if(BOOST_JSON_UNLIKELY(! cs))
1644 158 : return maybe_suspend(cs.begin(), state::sur6);
1645 2122 : digit = detail::hex_digit(*cs);
1646 2122 : if(BOOST_JSON_UNLIKELY(digit == -1))
1647 : {
1648 : BOOST_STATIC_CONSTEXPR source_location loc
1649 : = BOOST_CURRENT_LOCATION;
1650 20 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1651 : }
1652 2102 : ++cs;
1653 2102 : u2_ += digit;
1654 : // Check if the second code point is a valid trailing surrogate.
1655 : // Valid trailing surrogates are [DC00, DFFF]
1656 2102 : if(BOOST_JSON_UNLIKELY(
1657 : u2_ < 0xdc00 || u2_ > 0xdfff))
1658 : {
1659 : // If not valid and the parser does not allow it, return an error.
1660 580 : if(!allow_bad_utf16)
1661 : {
1662 : BOOST_STATIC_CONSTEXPR source_location loc
1663 : = BOOST_CURRENT_LOCATION;
1664 60 : return fail(cs.begin(), error::illegal_trailing_surrogate, &loc);
1665 : }
1666 : // Append the replacement character for the
1667 : // first leading surrogate.
1668 520 : temp.append_utf8(urc);
1669 : // Check if the second code point is a
1670 : // valid unicode scalar value (invalid leading
1671 : // or trailing surrogate)
1672 520 : if (u2_ < 0xd800 || u2_ > 0xdbff)
1673 : {
1674 220 : temp.append_utf8(u2_);
1675 220 : break;
1676 : }
1677 : // If it is a valid leading surrogate
1678 : else
1679 : {
1680 300 : u1_ = u2_;
1681 300 : goto do_sur1;
1682 : }
1683 : }
1684 : // Calculate the Unicode code point from the surrogate pair and
1685 : // append the UTF-8 representation.
1686 1522 : unsigned cp =
1687 1522 : ((u1_ - 0xd800) << 10) +
1688 1522 : ((u2_ - 0xdc00)) +
1689 : 0x10000;
1690 : // utf-16 surrogate pair
1691 1522 : temp.append_utf8(cp);
1692 : }
1693 :
1694 : // flush
1695 12653 : if(BOOST_JSON_UNLIKELY( !cs ) || *cs != '\\')
1696 8870 : break;
1697 : }
1698 :
1699 8870 : if(BOOST_JSON_LIKELY( temp.size() ))
1700 : {
1701 434 : BOOST_ASSERT(total <= max_size);
1702 8870 : if(BOOST_JSON_UNLIKELY( temp.size() > max_size - total ))
1703 : {
1704 : BOOST_STATIC_CONSTEXPR source_location loc
1705 : = BOOST_CURRENT_LOCATION;
1706 1 : return fail(cs.begin(), ev_too_large, &loc);
1707 : }
1708 :
1709 8869 : total += temp.size();
1710 8056 : bool const r = is_key
1711 8869 : ? h_.on_key_part(temp.get(), total, ec_)
1712 8152 : : h_.on_string_part(temp.get(), total, ec_);
1713 8056 : if(BOOST_JSON_UNLIKELY( !r ))
1714 813 : return fail( cs.begin() );
1715 : }
1716 :
1717 7243 : return cs.begin();
1718 : }
1719 :
1720 : //----------------------------------------------------------
1721 :
1722 : template<class Handler>
1723 : template<
1724 : bool StackEmpty_,
1725 : bool AllowComments_/*,
1726 : bool AllowTrailing_,
1727 : bool AllowBadUTF8_*/>
1728 : const char*
1729 109189 : basic_parser<Handler>::
1730 : parse_object(const char* p,
1731 : std::integral_constant<bool, StackEmpty_> stack_empty,
1732 : std::integral_constant<bool, AllowComments_> allow_comments,
1733 : /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
1734 : /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
1735 : bool allow_bad_utf16)
1736 : {
1737 109189 : detail::const_stream_wrapper cs(p, end_);
1738 : std::size_t size;
1739 109189 : if(! stack_empty && ! st_.empty())
1740 : {
1741 : // resume
1742 : state st;
1743 35058 : st_.pop(st);
1744 35058 : st_.pop(size);
1745 35058 : switch(st)
1746 : {
1747 : default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
1748 1595 : case state::obj1: goto do_obj1;
1749 235 : case state::obj2: goto do_obj2;
1750 12647 : case state::obj3: goto do_obj3;
1751 1690 : case state::obj4: goto do_obj4;
1752 251 : case state::obj5: goto do_obj5;
1753 1591 : case state::obj6: goto do_obj6;
1754 15448 : case state::obj7: goto do_obj7;
1755 426 : case state::obj8: goto do_obj8;
1756 660 : case state::obj9: goto do_obj9;
1757 181 : case state::obj10: goto do_obj10;
1758 334 : case state::obj11: goto do_obj11;
1759 : }
1760 : }
1761 74131 : BOOST_ASSERT(*cs == '{');
1762 74131 : size = 0;
1763 74131 : if(BOOST_JSON_UNLIKELY(! depth_))
1764 : {
1765 : BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1766 3 : return fail(cs.begin(), error::too_deep, &loc);
1767 : }
1768 74128 : --depth_;
1769 74128 : if(BOOST_JSON_UNLIKELY(
1770 : ! h_.on_object_begin(ec_)))
1771 2040 : return fail(cs.begin());
1772 70050 : ++cs;
1773 : // object:
1774 : // '{' *ws '}'
1775 : // '{' *ws string *ws ':' *ws value *ws *[ ',' *ws string *ws ':' *ws value *ws ] '}'
1776 73616 : do_obj1:
1777 73616 : cs = detail::count_whitespace(cs.begin(), cs.end());
1778 73616 : if(BOOST_JSON_UNLIKELY(! cs))
1779 1629 : return maybe_suspend(cs.begin(), state::obj1, size);
1780 71987 : if(BOOST_JSON_LIKELY(*cs != '}'))
1781 : {
1782 69088 : if(BOOST_JSON_UNLIKELY(*cs != '\x22'))
1783 : {
1784 2411 : if(allow_comments && *cs == '/')
1785 : {
1786 2139 : do_obj2:
1787 2374 : cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1788 2290 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1789 319 : return suspend_or_fail(state::obj2, size);
1790 1971 : goto do_obj1;
1791 : }
1792 : BOOST_STATIC_CONSTEXPR source_location loc
1793 : = BOOST_CURRENT_LOCATION;
1794 272 : return fail(cs.begin(), error::syntax, &loc);
1795 : }
1796 66677 : loop:
1797 80829 : if(BOOST_JSON_UNLIKELY(++size >
1798 : Handler::max_object_size))
1799 : {
1800 : BOOST_STATIC_CONSTEXPR source_location loc
1801 : = BOOST_CURRENT_LOCATION;
1802 1 : return fail(cs.begin(), error::object_too_large, &loc);
1803 : }
1804 80828 : do_obj3:
1805 93475 : cs = parse_string(cs.begin(), stack_empty, std::true_type(), allow_bad_utf8, allow_bad_utf16);
1806 90519 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1807 15592 : return suspend_or_fail(state::obj3, size);
1808 74927 : do_obj4:
1809 79088 : cs = detail::count_whitespace(cs.begin(), cs.end());
1810 79088 : if(BOOST_JSON_UNLIKELY(! cs))
1811 1705 : return maybe_suspend(cs.begin(), state::obj4, size);
1812 77383 : if(BOOST_JSON_UNLIKELY(*cs != ':'))
1813 : {
1814 2925 : if(allow_comments && *cs == '/')
1815 : {
1816 2779 : do_obj5:
1817 3030 : cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1818 2876 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1819 405 : return suspend_or_fail(state::obj5, size);
1820 2471 : goto do_obj4;
1821 : }
1822 : BOOST_STATIC_CONSTEXPR source_location loc
1823 : = BOOST_CURRENT_LOCATION;
1824 146 : return fail(cs.begin(), error::syntax, &loc);
1825 : }
1826 74458 : ++cs;
1827 76049 : do_obj6:
1828 76049 : cs = detail::count_whitespace(cs.begin(), cs.end());
1829 76049 : if(BOOST_JSON_UNLIKELY(! cs))
1830 1622 : return maybe_suspend(cs.begin(), state::obj6, size);
1831 74427 : do_obj7:
1832 89875 : cs = parse_value(cs.begin(), stack_empty, allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
1833 82526 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1834 23593 : return suspend_or_fail(state::obj7, size);
1835 58933 : do_obj8:
1836 61195 : cs = detail::count_whitespace(cs.begin(), cs.end());
1837 61195 : if(BOOST_JSON_UNLIKELY(! cs))
1838 441 : return maybe_suspend(cs.begin(), state::obj8, size);
1839 60754 : if(BOOST_JSON_LIKELY(*cs == ','))
1840 : {
1841 17792 : ++cs;
1842 19707 : do_obj9:
1843 19707 : cs = detail::count_whitespace(cs.begin(), cs.end());
1844 19707 : if(BOOST_JSON_UNLIKELY(! cs))
1845 690 : return maybe_suspend(cs.begin(), state::obj9, size);
1846 :
1847 : // loop for next element
1848 19017 : if(BOOST_JSON_LIKELY(*cs == '\x22'))
1849 14152 : goto loop;
1850 4865 : if(! allow_trailing || *cs != '}')
1851 : {
1852 1644 : if(allow_comments && *cs == '/')
1853 : {
1854 1433 : do_obj10:
1855 1614 : cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1856 1525 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1857 270 : return suspend_or_fail(state::obj10, size);
1858 1255 : goto do_obj9;
1859 : }
1860 : BOOST_STATIC_CONSTEXPR source_location loc
1861 : = BOOST_CURRENT_LOCATION;
1862 211 : return fail(cs.begin(), error::syntax, &loc);
1863 : }
1864 : }
1865 42962 : else if(BOOST_JSON_UNLIKELY(*cs != '}'))
1866 : {
1867 2325 : if(allow_comments && *cs == '/')
1868 : {
1869 2172 : do_obj11:
1870 2506 : cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1871 2338 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1872 502 : return suspend_or_fail(state::obj11, size);
1873 1836 : goto do_obj8;
1874 : }
1875 : BOOST_STATIC_CONSTEXPR source_location loc
1876 : = BOOST_CURRENT_LOCATION;
1877 153 : return fail(cs.begin(), error::syntax, &loc);
1878 : }
1879 : // got closing brace, fall through
1880 : }
1881 46757 : if(BOOST_JSON_UNLIKELY(
1882 : ! h_.on_object_end(size, ec_)))
1883 1502 : return fail(cs.begin());
1884 43714 : ++depth_;
1885 43714 : ++cs;
1886 43714 : return cs.begin();
1887 : }
1888 :
1889 : //----------------------------------------------------------
1890 :
1891 : template<class Handler>
1892 : template<
1893 : bool StackEmpty_,
1894 : bool AllowComments_/*,
1895 : bool AllowTrailing_,
1896 : bool AllowBadUTF8_*/>
1897 : const char*
1898 26348 : basic_parser<Handler>::
1899 : parse_array(const char* p,
1900 : std::integral_constant<bool, StackEmpty_> stack_empty,
1901 : std::integral_constant<bool, AllowComments_> allow_comments,
1902 : /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
1903 : /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
1904 : bool allow_bad_utf16)
1905 : {
1906 26348 : detail::const_stream_wrapper cs(p, end_);
1907 : std::size_t size;
1908 26348 : if(! stack_empty && ! st_.empty())
1909 : {
1910 : // resume
1911 : state st;
1912 5730 : st_.pop(st);
1913 5730 : st_.pop(size);
1914 5730 : switch(st)
1915 : {
1916 : default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
1917 1052 : case state::arr1: goto do_arr1;
1918 384 : case state::arr2: goto do_arr2;
1919 2938 : case state::arr3: goto do_arr3;
1920 391 : case state::arr4: goto do_arr4;
1921 671 : case state::arr5: goto do_arr5;
1922 294 : case state::arr6: goto do_arr6;
1923 : }
1924 : }
1925 20618 : BOOST_ASSERT(*cs == '[');
1926 20618 : size = 0;
1927 20618 : if(BOOST_JSON_UNLIKELY(! depth_))
1928 : {
1929 : BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1930 34 : return fail(cs.begin(), error::too_deep, &loc);
1931 : }
1932 20584 : --depth_;
1933 20584 : if(BOOST_JSON_UNLIKELY(
1934 : ! h_.on_array_begin(ec_)))
1935 812 : return fail(cs.begin());
1936 18966 : ++cs;
1937 : // array:
1938 : // '[' *ws ']'
1939 : // '[' *ws value *ws *[ ',' *ws value *ws ] ']'
1940 21551 : do_arr1:
1941 21551 : cs = detail::count_whitespace(cs.begin(), cs.end());
1942 21551 : if(BOOST_JSON_UNLIKELY(! cs))
1943 1073 : return maybe_suspend(cs.begin(), state::arr1, size);
1944 20478 : if(BOOST_JSON_LIKELY(*cs != ']'))
1945 : {
1946 18730 : loop:
1947 26193 : if(allow_comments && *cs == '/')
1948 : {
1949 1789 : do_arr2:
1950 2173 : cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1951 2045 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1952 512 : return suspend_or_fail(state::arr2, size);
1953 1533 : goto do_arr1;
1954 : }
1955 24404 : if(BOOST_JSON_UNLIKELY(++size >
1956 : Handler::max_array_size))
1957 : {
1958 : BOOST_STATIC_CONSTEXPR source_location loc
1959 : = BOOST_CURRENT_LOCATION;
1960 1 : return fail(cs.begin(), error::array_too_large, &loc);
1961 : }
1962 24403 : do_arr3:
1963 : // array is not empty, value required
1964 27341 : cs = parse_value(cs.begin(), stack_empty, allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
1965 24710 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1966 9052 : return suspend_or_fail(state::arr3, size);
1967 15658 : do_arr4:
1968 17279 : cs = detail::count_whitespace(cs.begin(), cs.end());
1969 17279 : if(BOOST_JSON_UNLIKELY(! cs))
1970 500 : return maybe_suspend(cs.begin(), state::arr4, size);
1971 16779 : if(BOOST_JSON_LIKELY(*cs == ','))
1972 : {
1973 9176 : ++cs;
1974 9847 : do_arr5:
1975 9847 : cs = detail::count_whitespace(cs.begin(), cs.end());
1976 9847 : if(BOOST_JSON_UNLIKELY(! cs))
1977 701 : return maybe_suspend(cs.begin(), state::arr5, size);
1978 : // loop for next element
1979 9146 : if(! allow_trailing || *cs != ']')
1980 7463 : goto loop;
1981 : }
1982 7603 : else if(BOOST_JSON_UNLIKELY(*cs != ']'))
1983 : {
1984 1969 : if(allow_comments && *cs == '/')
1985 : {
1986 1541 : do_arr6:
1987 1835 : cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1988 1688 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1989 458 : return suspend_or_fail(state::arr6, size);
1990 1230 : goto do_arr4;
1991 : }
1992 : BOOST_STATIC_CONSTEXPR source_location loc
1993 : = BOOST_CURRENT_LOCATION;
1994 428 : return fail(cs.begin(), error::syntax, &loc);
1995 : }
1996 : // got closing bracket; fall through
1997 : }
1998 9065 : if(BOOST_JSON_UNLIKELY(
1999 : ! h_.on_array_end(size, ec_)))
2000 547 : return fail(cs.begin());
2001 7939 : ++depth_;
2002 7939 : ++cs;
2003 7939 : return cs.begin();
2004 : }
2005 :
2006 : //----------------------------------------------------------
2007 :
2008 : template<class Handler>
2009 : template<bool StackEmpty_, char First_, number_precision Numbers_>
2010 : const char*
2011 10515990 : basic_parser<Handler>::
2012 : parse_number(const char* p,
2013 : std::integral_constant<bool, StackEmpty_> stack_empty,
2014 : std::integral_constant<char, First_> first,
2015 : std::integral_constant<number_precision, Numbers_> mode)
2016 : {
2017 10515990 : constexpr bool precise_parsing = mode == number_precision::precise;
2018 10515990 : constexpr bool no_parsing = mode == number_precision::none;
2019 :
2020 : // only one of these will be true if we are not resuming
2021 : // if negative then !zero_first && !nonzero_first
2022 : // if zero_first then !nonzero_first && !negative
2023 : // if nonzero_first then !zero_first && !negative
2024 10515990 : bool const negative = first == '-';
2025 10515990 : bool const zero_first = first == '0';
2026 10515990 : bool const nonzero_first = first == '+';
2027 10515990 : detail::const_stream_wrapper cs(p, end_);
2028 : number num;
2029 10515990 : const char* begin = cs.begin();
2030 10515990 : if(stack_empty || st_.empty())
2031 : {
2032 2089971 : num.bias = 0;
2033 2089971 : num.exp = 0;
2034 2089971 : num.frac = false;
2035 2089971 : num_buf_.clear();
2036 :
2037 : //----------------------------------
2038 : //
2039 : // '-'
2040 : // leading minus sign
2041 : //
2042 2089971 : BOOST_ASSERT(cs);
2043 : if(negative)
2044 25185 : ++cs;
2045 :
2046 2089971 : num.neg = negative;
2047 2089971 : num.frac = false;
2048 2089971 : num.exp = 0;
2049 2089971 : num.bias = 0;
2050 :
2051 : // fast path
2052 2089971 : if( cs.remain() >= 16 + 1 + 16 ) // digits . digits
2053 : {
2054 : int n1;
2055 :
2056 9989 : if( nonzero_first ||
2057 9989 : (negative && *cs != '0') )
2058 : {
2059 2007319 : n1 = detail::count_digits( cs.begin() );
2060 2007319 : BOOST_ASSERT(n1 >= 0 && n1 <= 16);
2061 :
2062 1837 : if( negative && n1 == 0 && opt_.allow_infinity_and_nan )
2063 : {
2064 9 : return parse_literal(
2065 : p - 1,
2066 8 : detail::literals_c<detail::literals::neg_infinity>());
2067 : }
2068 :
2069 1828 : if( ! nonzero_first && n1 == 0 )
2070 : {
2071 : // digit required
2072 : BOOST_STATIC_CONSTEXPR source_location loc
2073 : = BOOST_CURRENT_LOCATION;
2074 2 : return fail(cs.begin(), error::syntax, &loc);
2075 : }
2076 :
2077 : BOOST_IF_CONSTEXPR( !no_parsing )
2078 2006460 : num.mant = detail::parse_unsigned( 0, cs.begin(), n1 );
2079 : else
2080 848 : num.mant = 0;
2081 :
2082 2007308 : cs += n1;
2083 :
2084 : // integer or floating-point with
2085 : // >= 16 leading digits
2086 2007308 : if( n1 == 16 )
2087 : {
2088 2001425 : goto do_num2;
2089 : }
2090 : }
2091 : else
2092 : {
2093 : // 0. floating-point or 0e integer
2094 21187 : num.mant = 0;
2095 21187 : n1 = 0;
2096 21187 : ++cs;
2097 : }
2098 :
2099 : {
2100 27070 : const char c = *cs;
2101 27070 : if(c != '.')
2102 : {
2103 9871 : if((c | 32) == 'e')
2104 : {
2105 6576 : ++cs;
2106 6576 : goto do_exp1;
2107 : }
2108 : BOOST_IF_CONSTEXPR( negative && !no_parsing )
2109 20 : num.mant = ~num.mant + 1;
2110 3295 : goto finish_signed;
2111 : }
2112 : }
2113 :
2114 : // floating-point number
2115 :
2116 17199 : ++cs;
2117 :
2118 17199 : int n2 = detail::count_digits( cs.begin() );
2119 17199 : BOOST_ASSERT(n2 >= 0 && n2 <= 16);
2120 :
2121 17199 : if( n2 == 0 )
2122 : {
2123 : // digit required
2124 : BOOST_STATIC_CONSTEXPR source_location loc
2125 : = BOOST_CURRENT_LOCATION;
2126 3 : return fail(cs.begin(), error::syntax, &loc);
2127 : }
2128 :
2129 : // floating-point mantissa overflow
2130 17196 : if( n1 + n2 >= 19 )
2131 : {
2132 122 : goto do_num7;
2133 : }
2134 :
2135 : BOOST_IF_CONSTEXPR( !no_parsing )
2136 12855 : num.mant = detail::parse_unsigned( num.mant, cs.begin(), n2 );
2137 :
2138 17074 : BOOST_ASSERT(num.bias == 0);
2139 :
2140 17074 : num.bias -= n2;
2141 :
2142 17074 : cs += n2;
2143 :
2144 17074 : char ch = *cs;
2145 :
2146 17074 : if( (ch | 32) == 'e' )
2147 : {
2148 110 : ++cs;
2149 110 : goto do_exp1;
2150 : }
2151 16964 : else if( ch >= '0' && ch <= '9' )
2152 : {
2153 10017 : goto do_num8;
2154 : }
2155 :
2156 6947 : goto finish_dub;
2157 : }
2158 : }
2159 : else
2160 : {
2161 8426019 : num = num_;
2162 : state st;
2163 8426019 : st_.pop(st);
2164 8426019 : switch(st)
2165 : {
2166 : default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
2167 603 : case state::num1: goto do_num1;
2168 6460 : case state::num2: goto do_num2;
2169 4195112 : case state::num3: goto do_num3;
2170 52 : case state::num4: goto do_num4;
2171 4537 : case state::num5: goto do_num5;
2172 668 : case state::num6: goto do_num6;
2173 618 : case state::num7: goto do_num7;
2174 4205248 : case state::num8: goto do_num8;
2175 477 : case state::exp1: goto do_exp1;
2176 139 : case state::exp2: goto do_exp2;
2177 12105 : case state::exp3: goto do_exp3;
2178 : }
2179 : }
2180 :
2181 : //----------------------------------
2182 : //
2183 : // DIGIT
2184 : // first digit
2185 : //
2186 62068 : do_num1:
2187 15799 : if(zero_first || nonzero_first ||
2188 15799 : BOOST_JSON_LIKELY(cs))
2189 : {
2190 61345 : char const c = *cs;
2191 : if(zero_first)
2192 : {
2193 9726 : ++cs;
2194 9726 : num.mant = 0;
2195 9726 : goto do_num6;
2196 : }
2197 15076 : else if(nonzero_first || BOOST_JSON_LIKELY(
2198 : c >= '1' && c <= '9'))
2199 : {
2200 42790 : ++cs;
2201 42790 : num.mant = c - '0';
2202 : }
2203 8829 : else if(BOOST_JSON_UNLIKELY(
2204 : c == '0'))
2205 : {
2206 7634 : ++cs;
2207 7634 : num.mant = 0;
2208 7634 : goto do_num6;
2209 : }
2210 1195 : else if( (negative || num.neg) && opt_.allow_infinity_and_nan )
2211 : {
2212 1007 : st_.push(state::lit1);
2213 1007 : cur_lit_ = literal_index(detail::literals::neg_infinity);
2214 1007 : lit_offset_ = 1;
2215 1007 : return parse_literal(
2216 961 : cs.begin(), detail::literals_c<detail::literals::resume>() );
2217 : }
2218 : else
2219 : {
2220 : BOOST_STATIC_CONSTEXPR source_location loc
2221 : = BOOST_CURRENT_LOCATION;
2222 188 : return fail(cs.begin(), error::syntax, &loc);
2223 : }
2224 : }
2225 : else
2226 : {
2227 723 : if(BOOST_JSON_UNLIKELY(
2228 : ! h_.on_number_part(
2229 : {begin, cs.used(begin)}, ec_)))
2230 60 : return fail(cs.begin());
2231 :
2232 : BOOST_IF_CONSTEXPR( precise_parsing )
2233 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2234 HIT 603 : return maybe_suspend(
2235 603 : cs.begin(), state::num1, num);
2236 : }
2237 :
2238 : //----------------------------------
2239 : //
2240 : // 1*DIGIT
2241 : // significant digits left of decimal
2242 : //
2243 2050675 : do_num2:
2244 2044417 : if(negative || (!stack_empty && num.neg))
2245 : {
2246 22400 : for(;;)
2247 : {
2248 30225 : if(BOOST_JSON_UNLIKELY(! cs))
2249 : {
2250 1921 : if(BOOST_JSON_UNLIKELY(more_))
2251 : {
2252 1469 : if(BOOST_JSON_UNLIKELY(
2253 : ! h_.on_number_part(
2254 : {begin, cs.used(begin)}, ec_)))
2255 69 : return fail(cs.begin());
2256 :
2257 : BOOST_IF_CONSTEXPR( precise_parsing )
2258 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2259 HIT 1331 : return suspend(cs.begin(), state::num2, num);
2260 : }
2261 452 : goto finish_int;
2262 : }
2263 28304 : char const c = *cs;
2264 28304 : if(BOOST_JSON_LIKELY(
2265 : c >= '0' && c <= '9'))
2266 : {
2267 23223 : ++cs;
2268 : // 9223372036854775808 INT64_MIN
2269 23223 : if( num.mant > 922337203685477580 || (
2270 22508 : num.mant == 922337203685477580 && c > '8'))
2271 : break;
2272 : BOOST_IF_CONSTEXPR( !no_parsing )
2273 22141 : num.mant = 10 * num.mant + ( c - '0' );
2274 22400 : continue;
2275 : }
2276 5081 : goto do_num6; // [.eE]
2277 : }
2278 : }
2279 : else
2280 : {
2281 6889563 : for(;;)
2282 : {
2283 8932413 : if(BOOST_JSON_UNLIKELY(! cs))
2284 : {
2285 6588 : if(BOOST_JSON_UNLIKELY(more_))
2286 : {
2287 5975 : if(BOOST_JSON_UNLIKELY(
2288 : ! h_.on_number_part(
2289 : {begin, cs.used(begin)}, ec_)))
2290 426 : return fail(cs.begin());
2291 :
2292 : BOOST_IF_CONSTEXPR( precise_parsing )
2293 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2294 HIT 5129 : return suspend(cs.begin(), state::num2, num);
2295 : }
2296 613 : goto finish_int;
2297 : }
2298 8925825 : char const c = *cs;
2299 8925825 : if(BOOST_JSON_LIKELY(
2300 : c >= '0' && c <= '9'))
2301 : {
2302 6893607 : ++cs;
2303 : // 18446744073709551615 UINT64_MAX
2304 6893607 : if( num.mant > 1844674407370955161 || (
2305 6889985 : num.mant == 1844674407370955161 && c > '5'))
2306 : break;
2307 : BOOST_IF_CONSTEXPR( !no_parsing )
2308 6883965 : num.mant = 10 * num.mant + ( c - '0' );
2309 : }
2310 : else
2311 : {
2312 2032218 : goto do_num6; // [.eE]
2313 : }
2314 : }
2315 : }
2316 4867 : ++num.bias;
2317 :
2318 : //----------------------------------
2319 : //
2320 : // 1*DIGIT
2321 : // non-significant digits left of decimal
2322 : //
2323 4199979 : do_num3:
2324 4294978560 : for(;;)
2325 : {
2326 4299178539 : if(BOOST_JSON_UNLIKELY(! cs))
2327 : {
2328 4195839 : if(BOOST_JSON_UNLIKELY(more_))
2329 : {
2330 4195206 : if(BOOST_JSON_UNLIKELY(
2331 : ! h_.on_number_part(
2332 : {begin, cs.used(begin)}, ec_)))
2333 47 : return fail(cs.begin());
2334 :
2335 : BOOST_IF_CONSTEXPR( precise_parsing )
2336 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2337 HIT 4195112 : return suspend(cs.begin(), state::num3, num);
2338 : }
2339 633 : goto finish_dub;
2340 : }
2341 4294982700 : char const c = *cs;
2342 4294982700 : if(BOOST_JSON_UNLIKELY(
2343 : c >= '0' && c <= '9'))
2344 : {
2345 4294978561 : if(BOOST_JSON_UNLIKELY( num.bias + 1 == INT_MAX ))
2346 : {
2347 : BOOST_STATIC_CONSTEXPR source_location loc
2348 : = BOOST_CURRENT_LOCATION;
2349 1 : return fail(cs.begin(), error::exponent_overflow, &loc);
2350 : }
2351 4294978560 : ++cs;
2352 4294978560 : ++num.bias;
2353 : }
2354 4139 : else if(BOOST_JSON_LIKELY(
2355 : c == '.'))
2356 : {
2357 2028 : ++cs;
2358 2028 : break;
2359 : }
2360 2111 : else if((c | 32) == 'e')
2361 : {
2362 762 : ++cs;
2363 762 : goto do_exp1;
2364 : }
2365 : else
2366 : {
2367 1349 : goto finish_dub;
2368 : }
2369 : }
2370 :
2371 : //----------------------------------
2372 : //
2373 : // DIGIT
2374 : // first non-significant digit
2375 : // to the right of decimal
2376 : //
2377 2080 : do_num4:
2378 : {
2379 2080 : if(BOOST_JSON_UNLIKELY(! cs))
2380 : {
2381 64 : if(BOOST_JSON_UNLIKELY(
2382 : ! h_.on_number_part(
2383 : {begin, cs.used(begin)}, ec_)))
2384 6 : return fail(cs.begin());
2385 :
2386 : BOOST_IF_CONSTEXPR( precise_parsing )
2387 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2388 HIT 52 : return maybe_suspend(
2389 52 : cs.begin(), state::num4, num);
2390 : }
2391 2016 : char const c = *cs;
2392 2016 : if(BOOST_JSON_LIKELY(
2393 : //static_cast<unsigned char>(c - '0') < 10))
2394 : c >= '0' && c <= '9'))
2395 : {
2396 1949 : ++cs;
2397 : }
2398 : else
2399 : {
2400 : // digit required
2401 : BOOST_STATIC_CONSTEXPR source_location loc
2402 : = BOOST_CURRENT_LOCATION;
2403 67 : return fail(cs.begin(), error::syntax, &loc);
2404 : }
2405 : }
2406 :
2407 : //----------------------------------
2408 : //
2409 : // 1*DIGIT
2410 : // non-significant digits
2411 : // to the right of decimal
2412 : //
2413 2013470 : do_num5:
2414 37889832 : for(;;)
2415 : {
2416 39903302 : if(BOOST_JSON_UNLIKELY(! cs))
2417 : {
2418 6112 : if(BOOST_JSON_UNLIKELY(more_))
2419 : {
2420 4577 : if(BOOST_JSON_UNLIKELY(
2421 : ! h_.on_number_part(
2422 : {begin, cs.used(begin)}, ec_)))
2423 20 : return fail(cs.begin());
2424 :
2425 : BOOST_IF_CONSTEXPR( precise_parsing )
2426 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2427 HIT 4537 : return suspend(cs.begin(), state::num5, num);
2428 : }
2429 1535 : goto finish_dub;
2430 : }
2431 39897190 : char const c = *cs;
2432 39897190 : if(BOOST_JSON_LIKELY(
2433 : c >= '0' && c <= '9'))
2434 : {
2435 37889832 : ++cs;
2436 : }
2437 2007358 : else if((c | 32) == 'e')
2438 : {
2439 2003236 : ++cs;
2440 2003236 : goto do_exp1;
2441 : }
2442 : else
2443 : {
2444 4122 : goto finish_dub;
2445 : }
2446 : }
2447 :
2448 : //----------------------------------
2449 : //
2450 : // [.eE]
2451 : //
2452 2055327 : do_num6:
2453 : {
2454 2055327 : if(BOOST_JSON_UNLIKELY(! cs))
2455 : {
2456 800 : if(BOOST_JSON_UNLIKELY(more_))
2457 : {
2458 753 : if(BOOST_JSON_UNLIKELY(
2459 : ! h_.on_number_part(
2460 : {begin, cs.used(begin)}, ec_)))
2461 42 : return fail(cs.begin());
2462 :
2463 : BOOST_IF_CONSTEXPR( precise_parsing )
2464 2 : num_buf_.append( begin, cs.used(begin) );
2465 669 : return suspend(cs.begin(), state::num6, num);
2466 : }
2467 47 : goto finish_int;
2468 : }
2469 2054527 : char const c = *cs;
2470 2054527 : if(BOOST_JSON_LIKELY(
2471 : c == '.'))
2472 : {
2473 2016099 : ++cs;
2474 : }
2475 38428 : else if((c | 32) == 'e')
2476 : {
2477 9153 : ++cs;
2478 9153 : goto do_exp1;
2479 : }
2480 : else
2481 : {
2482 29275 : goto finish_int;
2483 : }
2484 : }
2485 :
2486 : //----------------------------------
2487 : //
2488 : // DIGIT
2489 : // first significant digit
2490 : // to the right of decimal
2491 : //
2492 2016839 : do_num7:
2493 : {
2494 2016839 : if(BOOST_JSON_UNLIKELY(! cs))
2495 : {
2496 693 : if(BOOST_JSON_UNLIKELY(more_))
2497 : {
2498 689 : if(BOOST_JSON_UNLIKELY(
2499 : ! h_.on_number_part(
2500 : {begin, cs.used(begin)}, ec_)))
2501 35 : return fail(cs.begin());
2502 :
2503 : BOOST_IF_CONSTEXPR( precise_parsing )
2504 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2505 HIT 619 : return suspend(cs.begin(), state::num7, num);
2506 : }
2507 : // digit required
2508 : BOOST_STATIC_CONSTEXPR source_location loc
2509 : = BOOST_CURRENT_LOCATION;
2510 4 : return fail(cs.begin(), error::syntax, &loc);
2511 : }
2512 2016146 : char const c = *cs;
2513 2016146 : if(BOOST_JSON_UNLIKELY(
2514 : c < '0' || c > '9'))
2515 : {
2516 : // digit required
2517 : BOOST_STATIC_CONSTEXPR source_location loc
2518 : = BOOST_CURRENT_LOCATION;
2519 169 : return fail(cs.begin(), error::syntax, &loc);
2520 : }
2521 : }
2522 :
2523 : //----------------------------------
2524 : //
2525 : // 1*DIGIT
2526 : // significant digits
2527 : // to the right of decimal
2528 : //
2529 6228742 : do_num8:
2530 4298245220 : for(;;)
2531 : {
2532 4304476462 : if(BOOST_JSON_UNLIKELY(! cs))
2533 : {
2534 4207120 : if(BOOST_JSON_UNLIKELY(more_))
2535 : {
2536 4205384 : if(BOOST_JSON_UNLIKELY(
2537 : ! h_.on_number_part(
2538 : {begin, cs.used(begin)}, ec_)))
2539 67 : return fail(cs.begin());
2540 :
2541 : BOOST_IF_CONSTEXPR( precise_parsing )
2542 2 : num_buf_.append( begin, cs.used(begin) );
2543 4205249 : return suspend(cs.begin(), state::num8, num);
2544 : }
2545 1736 : goto finish_dub;
2546 : }
2547 4300269342 : char const c = *cs;
2548 4300269342 : if(BOOST_JSON_LIKELY(
2549 : c >= '0' && c <= '9'))
2550 : {
2551 4300252205 : ++cs;
2552 4300247112 : if(!no_parsing && BOOST_JSON_LIKELY(
2553 : num.mant <= 9007199254740991)) // 2^53-1
2554 : {
2555 4298245221 : if(BOOST_JSON_UNLIKELY( num.bias - 1 == INT_MIN ))
2556 : {
2557 : BOOST_STATIC_CONSTEXPR source_location loc
2558 : = BOOST_CURRENT_LOCATION;
2559 1 : return fail(cs.begin(), error::exponent_overflow, &loc);
2560 : }
2561 4298245220 : --num.bias;
2562 4298245220 : num.mant = 10 * num.mant + ( c - '0' );
2563 : }
2564 : else
2565 : {
2566 2006984 : goto do_num5;
2567 : }
2568 : }
2569 17137 : else if((c | 32) == 'e')
2570 : {
2571 11134 : ++cs;
2572 11134 : goto do_exp1;
2573 : }
2574 : else
2575 : {
2576 6003 : goto finish_dub;
2577 : }
2578 : }
2579 :
2580 : //----------------------------------
2581 : //
2582 : // *[+-]
2583 : //
2584 2031448 : do_exp1:
2585 2031448 : if(BOOST_JSON_UNLIKELY(! cs))
2586 : {
2587 575 : if(BOOST_JSON_UNLIKELY(
2588 : ! h_.on_number_part(
2589 : {begin, cs.used(begin)}, ec_)))
2590 49 : return fail(cs.begin());
2591 :
2592 : BOOST_IF_CONSTEXPR( precise_parsing )
2593 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2594 HIT 477 : return maybe_suspend(
2595 477 : cs.begin(), state::exp1, num);
2596 : }
2597 2030873 : if(*cs == '+')
2598 : {
2599 2364 : ++cs;
2600 : }
2601 2028509 : else if(*cs == '-')
2602 : {
2603 1001936 : ++cs;
2604 1001936 : num.frac = true;
2605 : }
2606 :
2607 : //----------------------------------
2608 : //
2609 : // DIGIT
2610 : // first digit of the exponent
2611 : //
2612 1026573 : do_exp2:
2613 : {
2614 2031012 : if(BOOST_JSON_UNLIKELY(! cs))
2615 : {
2616 188 : if(BOOST_JSON_UNLIKELY(more_))
2617 : {
2618 179 : if(BOOST_JSON_UNLIKELY(
2619 : ! h_.on_number_part(
2620 : {begin, cs.used(begin)}, ec_)))
2621 20 : return fail(cs.begin());
2622 :
2623 : BOOST_IF_CONSTEXPR( precise_parsing )
2624 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2625 HIT 139 : return suspend(cs.begin(), state::exp2, num);
2626 : }
2627 : // digit required
2628 : BOOST_STATIC_CONSTEXPR source_location loc
2629 : = BOOST_CURRENT_LOCATION;
2630 9 : return fail(cs.begin(), error::syntax, &loc);
2631 : }
2632 2030824 : char const c = *cs;
2633 2030824 : if(BOOST_JSON_UNLIKELY(
2634 : c < '0' || c > '9'))
2635 : {
2636 : // digit required
2637 : BOOST_STATIC_CONSTEXPR source_location loc
2638 : = BOOST_CURRENT_LOCATION;
2639 508 : return fail(cs.begin(), error::syntax, &loc);
2640 : }
2641 2030316 : ++cs;
2642 2030316 : num.exp = c - '0';
2643 : }
2644 :
2645 : //----------------------------------
2646 : //
2647 : // 1*DIGIT
2648 : // subsequent digits in the exponent
2649 : //
2650 2042421 : do_exp3:
2651 5468163 : for(;;)
2652 : {
2653 7510584 : if(BOOST_JSON_UNLIKELY(! cs))
2654 : {
2655 2020838 : if(BOOST_JSON_UNLIKELY(more_))
2656 : {
2657 12277 : if(BOOST_JSON_UNLIKELY(
2658 : ! h_.on_number_part(
2659 : {begin, cs.used(begin)}, ec_)))
2660 86 : return fail(cs.begin());
2661 :
2662 : BOOST_IF_CONSTEXPR( precise_parsing )
2663 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2664 HIT 12105 : return suspend(cs.begin(), state::exp3, num);
2665 : }
2666 : }
2667 : else
2668 : {
2669 5489746 : char const c = *cs;
2670 5489746 : if(BOOST_JSON_LIKELY( c >= '0' && c <= '9' ))
2671 : {
2672 5468163 : if(BOOST_JSON_UNLIKELY(
2673 : // 2147483647 INT_MAX
2674 : num.exp > 214748364 ||
2675 : (num.exp == 214748364 && c > '7')
2676 : ))
2677 3855 : num.exp = INT_MAX;
2678 : else BOOST_IF_CONSTEXPR( !no_parsing )
2679 4923456 : num.exp = 10 * num.exp + ( c - '0' );
2680 :
2681 5468163 : ++cs;
2682 5468163 : continue;
2683 : }
2684 : }
2685 2030144 : BOOST_ASSERT(num.exp >= 0);
2686 2030144 : if ( num.frac )
2687 : {
2688 1001800 : if(BOOST_JSON_UNLIKELY( num.bias < (INT_MIN + num.exp) ))
2689 : {
2690 : // if exponent overflowed, bias is a very large negative
2691 : // number, and mantissa isn't zero, then we cannot parse the
2692 : // number correctly
2693 92 : if(BOOST_JSON_UNLIKELY(
2694 : (num.exp == INT_MAX) &&
2695 : (num.bias < 0) &&
2696 : (num.exp + num.bias < 308) &&
2697 : num.mant ))
2698 : {
2699 : BOOST_STATIC_CONSTEXPR source_location loc
2700 : = BOOST_CURRENT_LOCATION;
2701 1 : return fail(cs.begin(), error::exponent_overflow, &loc);
2702 : }
2703 :
2704 91 : num.bias = 0;
2705 91 : num.exp = INT_MAX;
2706 : }
2707 : }
2708 1028344 : else if (BOOST_JSON_UNLIKELY( num.bias > (INT_MAX - num.exp) ))
2709 : {
2710 : // if exponent overflowed, bias is a very large positive number,
2711 : // and mantissa isn't zero, then we cannot parse the
2712 : // number correctly
2713 194 : if(BOOST_JSON_UNLIKELY(
2714 : (num.exp == INT_MAX) &&
2715 : (num.bias > 0) &&
2716 : (num.exp - num.bias < 308) &&
2717 : num.mant ))
2718 : {
2719 : BOOST_STATIC_CONSTEXPR source_location loc
2720 : = BOOST_CURRENT_LOCATION;
2721 1 : return fail(cs.begin(), error::exponent_overflow, &loc);
2722 : }
2723 :
2724 193 : num.bias = 0;
2725 193 : num.exp = INT_MAX;
2726 : }
2727 2030142 : goto finish_dub;
2728 : }
2729 :
2730 30387 : finish_int:
2731 28458 : if(negative || (!stack_empty && num.neg))
2732 : {
2733 2531 : if(BOOST_JSON_UNLIKELY(
2734 : ! h_.on_int64(static_cast<
2735 : int64_t>(~num.mant + 1), {begin, cs.used(begin)}, ec_)))
2736 310 : return fail(cs.begin());
2737 1913 : return cs.begin();
2738 : }
2739 27856 : if(num.mant <= INT64_MAX)
2740 : {
2741 27555 : finish_signed:
2742 30830 : if(BOOST_JSON_UNLIKELY(
2743 : ! h_.on_int64(static_cast<
2744 : int64_t>(num.mant), {begin, cs.used(begin)}, ec_)))
2745 2267 : return fail(cs.begin());
2746 26303 : return cs.begin();
2747 : }
2748 321 : if(BOOST_JSON_UNLIKELY(
2749 : ! h_.on_uint64(num.mant, {begin, cs.used(begin)}, ec_)))
2750 35 : return fail(cs.begin());
2751 254 : return cs.begin();
2752 2052467 : finish_dub:
2753 : double d;
2754 2052467 : std::size_t const size = cs.used(begin);
2755 2052467 : BOOST_ASSERT( !num_buf_.size() || precise_parsing );
2756 : BOOST_IF_CONSTEXPR( precise_parsing )
2757 : {
2758 1000052 : char const* data = begin;
2759 1000052 : std::size_t full_size = size;
2760 : // if we previously suspended or if the current input ends with the
2761 : // number, we need to copy the current part of the number to the
2762 : // temporary buffer
2763 1000052 : if(BOOST_JSON_UNLIKELY( num_buf_.size() ))
2764 : {
2765 1 : data = num_buf_.append( begin, size );
2766 1 : full_size = num_buf_.size();
2767 : }
2768 1000052 : auto const err = detail::charconv::from_chars(
2769 : data, data + full_size, d );
2770 1000052 : BOOST_ASSERT( err.ec != std::errc::invalid_argument );
2771 1000052 : BOOST_ASSERT( err.ptr == data + full_size );
2772 : (void)err;
2773 : }
2774 : else BOOST_IF_CONSTEXPR( no_parsing )
2775 9258 : d = 0;
2776 : else
2777 1043157 : d = detail::dec_to_float(
2778 : num.mant,
2779 541045 : num.bias + (num.frac ?
2780 502112 : -num.exp : num.exp),
2781 1043157 : num.neg);
2782 2052467 : if(BOOST_JSON_UNLIKELY(
2783 : ! h_.on_double(d, {begin, size}, ec_)))
2784 1935 : return fail(cs.begin());
2785 2048597 : return cs.begin();
2786 : }
2787 :
2788 : //----------------------------------------------------------
2789 :
2790 : template<class Handler>
2791 : template<class... Args>
2792 2164987 : basic_parser<Handler>::
2793 : basic_parser(
2794 : parse_options const& opt,
2795 : Args&&... args)
2796 2164978 : : h_(std::forward<Args>(args)...)
2797 2164987 : , opt_(opt)
2798 : {
2799 2164987 : }
2800 :
2801 : //----------------------------------------------------------
2802 :
2803 : template<class Handler>
2804 : void
2805 4153166 : basic_parser<Handler>::
2806 : reset() noexcept
2807 : {
2808 4153166 : ec_ = {};
2809 4153166 : st_.clear();
2810 4153166 : more_ = true;
2811 4153166 : done_ = false;
2812 4153166 : clean_ = true;
2813 4153166 : num_buf_.clear();
2814 4153166 : }
2815 :
2816 : template<class Handler>
2817 : void
2818 18 : basic_parser<Handler>::
2819 : fail(system::error_code ec) noexcept
2820 : {
2821 18 : if(! ec)
2822 : {
2823 : // assign an arbitrary
2824 : // error code to prevent UB
2825 1 : BOOST_JSON_FAIL(ec_, error::incomplete);
2826 : }
2827 : else
2828 : {
2829 17 : ec_ = ec;
2830 : }
2831 18 : done_ = false;
2832 18 : }
2833 :
2834 : //----------------------------------------------------------
2835 :
2836 : template<class Handler>
2837 : std::size_t
2838 10726454 : basic_parser<Handler>::
2839 : write_some(
2840 : bool more,
2841 : char const* data,
2842 : std::size_t size,
2843 : system::error_code& ec)
2844 : {
2845 : // see if we exited via exception
2846 : // on the last call to write_some
2847 10726454 : if(! clean_)
2848 : {
2849 : // prevent UB
2850 1 : if(! ec_)
2851 : {
2852 1 : BOOST_JSON_FAIL(ec_, error::exception);
2853 : }
2854 : }
2855 10726454 : if(ec_)
2856 : {
2857 : // error is sticky
2858 5 : ec = ec_;
2859 5 : return 0;
2860 : }
2861 10726449 : clean_ = false;
2862 10726449 : more_ = more;
2863 10726449 : end_ = data + size;
2864 : const char* p;
2865 10726449 : if(BOOST_JSON_LIKELY(st_.empty()))
2866 : {
2867 : // first time
2868 2164976 : depth_ = opt_.max_depth;
2869 2164976 : if(BOOST_JSON_UNLIKELY(
2870 : ! h_.on_document_begin(ec_)))
2871 : {
2872 7928 : ec = ec_;
2873 7928 : return 0;
2874 : }
2875 2149119 : p = parse_document(data, std::true_type());
2876 : }
2877 : else
2878 : {
2879 8561473 : p = parse_document(data, std::false_type());
2880 : }
2881 :
2882 10691424 : if(BOOST_JSON_LIKELY(p != sentinel()))
2883 : {
2884 2099195 : BOOST_ASSERT(! ec_);
2885 2099195 : if(! done_)
2886 : {
2887 2031780 : done_ = true;
2888 2031780 : h_.on_document_end(ec_);
2889 : }
2890 : }
2891 : else
2892 : {
2893 8592229 : if(! ec_)
2894 : {
2895 8565374 : if(! more_)
2896 : {
2897 589 : BOOST_JSON_FAIL(ec_, error::incomplete);
2898 : }
2899 8564785 : else if(! st_.empty())
2900 : {
2901 : // consume as much trailing whitespace in
2902 : // the JSON document as possible, but still
2903 : // consider the parse complete
2904 : state st;
2905 8564785 : st_.peek(st);
2906 8564785 : if( st == state::doc3 &&
2907 88551 : ! done_)
2908 : {
2909 70724 : done_ = true;
2910 70724 : h_.on_document_end(ec_);
2911 : }
2912 : }
2913 : }
2914 8590585 : p = end_;
2915 : }
2916 10685788 : ec = ec_;
2917 10685788 : clean_ = true;
2918 10685788 : return p - data;
2919 : }
2920 :
2921 : template<class Handler>
2922 : std::size_t
2923 1 : basic_parser<Handler>::
2924 : write_some(
2925 : bool more,
2926 : char const* data,
2927 : std::size_t size,
2928 : std::error_code& ec)
2929 : {
2930 1 : system::error_code jec;
2931 1 : std::size_t const result = write_some(more, data, size, jec);
2932 1 : ec = jec;
2933 1 : return result;
2934 : }
2935 :
2936 : #endif
2937 :
2938 : } // namespace json
2939 : } // namespace boost
2940 :
2941 : #ifdef _MSC_VER
2942 : #pragma warning(pop)
2943 : #endif
2944 :
2945 : #endif
|