33
33
#include " my_rapidjson_size_t.h" // IWYU pragma: keep
34
34
35
35
#include < assert.h>
36
- #include < rapidjson/encodings.h>
37
- #include < rapidjson/memorystream.h> // rapidjson::MemoryStream
38
36
#include < stddef.h>
39
37
#include < algorithm> // any_of
40
- #include < memory> // unique_ptr
41
38
#include < string>
39
+ #include < string_view>
40
+
41
+ #include < rapidjson/encodings.h>
42
+ #include < rapidjson/error/error.h>
43
+ #include < rapidjson/memorystream.h>
44
+ #include < rapidjson/reader.h>
42
45
43
46
#include " my_inttypes.h"
44
47
#include " mysql/strings/m_ctype.h"
47
50
#include " sql/sql_const.h" // STRING_BUFFER_USUAL_SIZE
48
51
#include " sql_string.h" // String
49
52
#include " string_with_len.h"
50
- #include " template_utils.h" // down_cast
51
53
52
54
namespace {
53
55
@@ -64,15 +66,15 @@ class Stream;
64
66
65
67
} // namespace
66
68
67
- static bool is_ecmascript_identifier (const std::string &name);
69
+ static bool is_ecmascript_identifier (const std::string_view &name);
68
70
static bool is_digit (unsigned codepoint);
69
71
static bool is_whitespace (char );
70
72
71
- static bool parse_path (Stream *, Json_path *, const JsonErrorHandler & );
72
- static bool parse_path_leg (Stream *, Json_path *, const JsonErrorHandler & );
73
+ static bool parse_path (Stream *, Json_path *);
74
+ static bool parse_path_leg (Stream *, Json_path *);
73
75
static bool parse_ellipsis_leg (Stream *, Json_path *);
74
76
static bool parse_array_leg (Stream *, Json_path *);
75
- static bool parse_member_leg (Stream *, Json_path *, const JsonErrorHandler & );
77
+ static bool parse_member_leg (Stream *, Json_path *);
76
78
77
79
static bool append_array_index (String *buf, size_t index, bool from_end) {
78
80
if (!from_end) return buf->append_ulonglong (index );
@@ -253,10 +255,9 @@ class Stream {
253
255
254
256
/* * Top level parsing factory method */
255
257
bool parse_path (size_t path_length, const char *path_expression,
256
- Json_path *path, size_t *bad_index,
257
- const JsonErrorHandler &depth_handler) {
258
+ Json_path *path, size_t *bad_index) {
258
259
Stream stream (path_expression, path_length);
259
- if (parse_path (&stream, path, depth_handler )) {
260
+ if (parse_path (&stream, path)) {
260
261
*bad_index = stream.position () - path_expression;
261
262
return true ;
262
263
}
@@ -275,13 +276,10 @@ static inline bool is_whitespace(char ch) {
275
276
276
277
@param[in,out] stream The stream to read the path expression from.
277
278
@param[in,out] path The Json_path object to fill.
278
- @param[in] depth_handler Pointer to a function that should handle error
279
- occurred when depth is exceeded.
280
279
281
280
@return true on error, false on success
282
281
*/
283
- static bool parse_path (Stream *stream, Json_path *path,
284
- const JsonErrorHandler &depth_handler) {
282
+ static bool parse_path (Stream *stream, Json_path *path) {
285
283
path->clear ();
286
284
287
285
// the first non-whitespace character must be $
@@ -291,7 +289,7 @@ static bool parse_path(Stream *stream, Json_path *path,
291
289
// now add the legs
292
290
stream->skip_whitespace ();
293
291
while (!stream->exhausted ()) {
294
- if (parse_path_leg (stream, path, depth_handler )) return true ;
292
+ if (parse_path_leg (stream, path)) return true ;
295
293
stream->skip_whitespace ();
296
294
}
297
295
@@ -308,18 +306,15 @@ static bool parse_path(Stream *stream, Json_path *path,
308
306
309
307
@param[in,out] stream The stream to read the path expression from.
310
308
@param[in,out] path The Json_path object to fill.
311
- @param[in] depth_handler Pointer to a function that should handle error
312
- occurred when depth is exceeded.
313
309
314
310
@return true on error, false on success
315
311
*/
316
- static bool parse_path_leg (Stream *stream, Json_path *path,
317
- const JsonErrorHandler &depth_handler) {
312
+ static bool parse_path_leg (Stream *stream, Json_path *path) {
318
313
switch (stream->peek ()) {
319
314
case BEGIN_ARRAY:
320
315
return parse_array_leg (stream, path);
321
316
case BEGIN_MEMBER:
322
- return parse_member_leg (stream, path, depth_handler );
317
+ return parse_member_leg (stream, path);
323
318
case WILDCARD:
324
319
return parse_ellipsis_leg (stream, path);
325
320
default :
@@ -539,6 +534,28 @@ static const char *find_end_of_member_name(const char *start, const char *end) {
539
534
return std::find_if (str, end, is_terminator);
540
535
}
541
536
537
+ namespace {
538
+ // / A RapidJSON handler which accepts a scalar string and nothing else.
539
+ class MemberNameHandler
540
+ : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>,
541
+ MemberNameHandler> {
542
+ public:
543
+ explicit MemberNameHandler (::String *name) : m_name(name) {}
544
+
545
+ bool String (const char *str, size_t length, bool ) {
546
+ return !m_name->copy (str, length, &my_charset_utf8mb4_bin);
547
+ }
548
+
549
+ bool Default () {
550
+ assert (false );
551
+ return false ;
552
+ }
553
+
554
+ private:
555
+ ::String *m_name;
556
+ };
557
+ } // namespace
558
+
542
559
/* *
543
560
Parse a quoted member name using the rapidjson parser, so that we
544
561
get the name without the enclosing quotes and with any escape
@@ -549,34 +566,25 @@ static const char *find_end_of_member_name(const char *start, const char *end) {
549
566
550
567
@param str the input string
551
568
@param len the length of the input string
552
- @param depth_handler Pointer to a function that should handle error
553
- occurred when depth is exceeded.
554
- @return a Json_string that represents the member name, or NULL if
555
- the input string is not a valid name
569
+ @param[out] name the member name
570
+ @return false on success, true on error
556
571
*/
557
- static std::unique_ptr<Json_string> parse_name_with_rapidjson (
558
- const char *str, size_t len, const JsonErrorHandler &depth_handler) {
559
- Json_dom_ptr dom = Json_dom::parse (
560
- str, len, [](const char *, size_t ) {}, depth_handler);
561
-
562
- if (dom == nullptr || dom->json_type () != enum_json_type::J_STRING)
563
- return nullptr ;
564
-
565
- return std::unique_ptr<Json_string>(down_cast<Json_string *>(dom.release ()));
572
+ bool parse_name_with_rapidjson (const char *str, size_t len, String *name) {
573
+ MemberNameHandler handler (name);
574
+ rapidjson::MemoryStream stream (str, len);
575
+ rapidjson::Reader reader;
576
+ return !reader.Parse <rapidjson::kParseDefaultFlags >(stream, handler);
566
577
}
567
578
568
579
/* *
569
580
Parses a single member leg and appends it to a Json_path object.
570
581
571
582
@param[in,out] stream The stream to read the path expression from.
572
583
@param[in,out] path The Json_path object to fill.
573
- @param[in] depth_handler Pointer to a function that should handle error
574
- occurred when depth is exceeded.
575
584
576
585
@return true on error, false on success
577
586
*/
578
- static bool parse_member_leg (Stream *stream, Json_path *path,
579
- const JsonErrorHandler &depth_handler) {
587
+ static bool parse_member_leg (Stream *stream, Json_path *path) {
580
588
// advance past the .
581
589
assert (stream->peek () == BEGIN_MEMBER);
582
590
stream->skip (1 );
@@ -596,15 +604,16 @@ static bool parse_member_leg(Stream *stream, Json_path *path,
596
604
const bool was_quoted = (*key_start == DOUBLE_QUOTE);
597
605
stream->skip (key_end - key_start);
598
606
599
- std::unique_ptr<Json_string> jstr ;
607
+ StringBuffer<STRING_BUFFER_USUAL_SIZE> name ;
600
608
601
609
if (was_quoted) {
602
610
/*
603
611
Send the quoted name through the parser to unquote and
604
612
unescape it.
605
613
*/
606
- jstr = parse_name_with_rapidjson (key_start, key_end - key_start,
607
- depth_handler);
614
+ if (parse_name_with_rapidjson (key_start, key_end - key_start, &name)) {
615
+ return true ;
616
+ }
608
617
} else {
609
618
/*
610
619
An unquoted name may contain escape sequences. Wrap it in
@@ -616,17 +625,18 @@ static bool parse_member_leg(Stream *stream, Json_path *path,
616
625
strbuff.append (key_start, key_end - key_start) ||
617
626
strbuff.append (DOUBLE_QUOTE))
618
627
return true ; /* purecov: inspected */
619
- jstr = parse_name_with_rapidjson (strbuff.ptr (), strbuff.length (),
620
- depth_handler);
628
+ if (parse_name_with_rapidjson (strbuff.ptr (), strbuff.length (), &name)) {
629
+ return true ;
630
+ }
621
631
}
622
632
623
- if (jstr == nullptr ) return true ;
624
-
625
633
// unquoted names must be valid ECMAScript identifiers
626
- if (!was_quoted && !is_ecmascript_identifier (jstr->value ())) return true ;
634
+ if (!was_quoted && !is_ecmascript_identifier ({name.ptr (), name.length ()})) {
635
+ return true ;
636
+ }
627
637
628
638
// Looking good.
629
- if (path->append (Json_path_leg (jstr-> value ())))
639
+ if (path->append (Json_path_leg (name. ptr (), name. length ())))
630
640
return true ; /* purecov: inspected */
631
641
}
632
642
@@ -711,7 +721,7 @@ static bool is_connector_punctuation(unsigned codepoint) {
711
721
712
722
@return True if the name is a valid ECMAScript identifier. False otherwise.
713
723
*/
714
- static bool is_ecmascript_identifier (const std::string &name) {
724
+ static bool is_ecmascript_identifier (const std::string_view &name) {
715
725
// An empty string is not a valid identifier.
716
726
if (name.empty ()) return false ;
717
727
0 commit comments