Coverage Report

Created: 2024-06-18 07:03

/src/server/include/json_lib.h
Line
Count
Source (jump to first uncovered line)
1
#ifndef JSON_LIB_INCLUDED
2
#define JSON_LIB_INCLUDED
3
4
#include <my_sys.h>
5
6
#ifdef __cplusplus
7
extern "C" {
8
#endif
9
10
9.09k
#define JSON_DEPTH_LIMIT 32
11
12
/*
13
  When error happens, the c_next of the JSON engine contains the
14
  character that caused the error, and the c_str is the position
15
  in string where the error occurs.
16
*/
17
enum json_errors {
18
  JE_BAD_CHR= -1,      /* Invalid character, charset handler cannot read it. */
19
20
  JE_NOT_JSON_CHR= -2, /* Character met not used in JSON. */
21
                       /* ASCII 00-08 for instance.       */
22
23
  JE_EOS= -3,          /* Unexpected end of string. */
24
25
  JE_SYN= -4,          /* The next character breaks the JSON syntax. */
26
27
  JE_STRING_CONST= -5, /* Character disallowed in string constant. */
28
29
  JE_ESCAPING= -6,     /* Error in the escaping. */
30
31
  JE_DEPTH= -7,        /* The limit on the JSON depth was overrun. */
32
};
33
34
35
typedef struct st_json_string_t
36
{
37
  const uchar *c_str;    /* Current position in JSON string */
38
  const uchar *str_end;  /* The end on the string. */
39
  my_wc_t c_next;        /* UNICODE of the last read character */
40
  int c_next_len;        /* character lenght of the last read character. */
41
  int error;             /* error code. */
42
43
  CHARSET_INFO *cs;      /* Character set of the JSON string. */
44
45
  my_charset_conv_mb_wc wc; /* UNICODE conversion function. */
46
                            /* It's taken out of the cs just to speed calls. */
47
} json_string_t;
48
49
50
void json_string_set_cs(json_string_t *s, CHARSET_INFO *i_cs);
51
void json_string_set_str(json_string_t *s,
52
                         const uchar *str, const uchar *end);
53
#define json_next_char(j) \
54
196k
  ((j)->c_next_len= (j)->wc((j)->cs, &(j)->c_next, (j)->c_str, (j)->str_end))
55
9.16k
#define json_eos(j) ((j)->c_str >= (j)->str_end)
56
/*
57
  read_string_const_chr() reads the next character of the string constant
58
  and saves it to the js->c_next.
59
  It takes into account possible escapings, so if for instance
60
  the string is '\b', the read_string_const_chr() sets 8.
61
*/
62
int json_read_string_const_chr(json_string_t *js);
63
64
65
/*
66
  Various JSON-related operations expect JSON path as a parameter.
67
  The path is a string like this "$.keyA[2].*"
68
  The path itself is a number of steps specifying either a key or a position
69
  in an array. Some of them can be wildcards.
70
  So the representation of the JSON path is the json_path_t class
71
  containing an array of json_path_step_t objects.
72
*/
73
74
75
/* Path step types - actually bitmasks to let '&' or '|' operations. */
76
enum json_path_step_types
77
{
78
  JSON_PATH_KEY_NULL=0,
79
  JSON_PATH_KEY=1,   /* Must be equal to JSON_VALUE_OBJECT. */
80
  JSON_PATH_ARRAY=2, /* Must be equal to JSON_VALUE_ARRAY. */
81
  JSON_PATH_KEY_OR_ARRAY=3,
82
  JSON_PATH_WILD=4, /* Step like .* or [*] */
83
  JSON_PATH_DOUBLE_WILD=8, /* Step like **.k or **[1] */
84
  JSON_PATH_KEY_WILD= 1+4,
85
  JSON_PATH_KEY_DOUBLEWILD= 1+8,
86
  JSON_PATH_ARRAY_WILD= 2+4,
87
  JSON_PATH_ARRAY_DOUBLEWILD= 2+8,
88
  JSON_PATH_NEGATIVE_INDEX= 16,
89
  JSON_PATH_ARRAY_RANGE= 32
90
};
91
92
93
typedef struct st_json_path_step_t
94
{
95
  enum json_path_step_types type;  /* The type of the step -   */
96
                                   /* see json_path_step_types */
97
  const uchar *key; /* Pointer to the beginning of the key. */
98
  const uchar *key_end;  /* Pointer to the end of the key. */
99
  int n_item;  /* Item number in an array. No meaning for the key step. */
100
  int n_item_end; /* Last index of the range. */
101
} json_path_step_t;
102
103
104
typedef struct st_json_path_t
105
{
106
  json_string_t s;  /* The string to be parsed. */
107
  json_path_step_t steps[JSON_DEPTH_LIMIT]; /* Steps of the path. */
108
  json_path_step_t *last_step; /* Points to the last step. */
109
110
  int mode_strict; /* TRUE if the path specified as 'strict' */
111
  enum json_path_step_types types_used; /* The '|' of all step's 'type'-s */
112
} json_path_t;
113
114
115
int json_path_setup(json_path_t *p,
116
                    CHARSET_INFO *i_cs, const uchar *str, const uchar *end);
117
118
119
/*
120
  The set of functions and structures below provides interface
121
  to the JSON text parser.
122
  Running the parser normally goes like this:
123
124
    json_engine_t j_eng;   // structure keeps parser's data
125
    json_scan_start(j_eng) // begin the parsing
126
127
    do
128
    {
129
      // The parser has read next piece of JSON
130
      // and set fields of j_eng structure accordingly.
131
      // So let's see what we have:
132
      switch (j_eng.state)
133
      {
134
        case JST_KEY:
135
           // Handle key name. See the json_read_keyname_chr()
136
           // Probably compare it with the keyname we're looking for
137
        case JST_VALUE:
138
           // Handle value. It is either value of the key or an array item.
139
           // see the json_read_value()
140
        case JST_OBJ_START:
141
          // parser found an object (the '{' in JSON)
142
        case JST_OBJ_END:
143
          // parser found the end of the object (the '}' in JSON)
144
        case JST_ARRAY_START:
145
          // parser found an array (the '[' in JSON)
146
        case JST_ARRAY_END:
147
          // parser found the end of the array (the ']' in JSON)
148
149
      };
150
    } while (json_scan_next() == 0);  // parse next structure
151
152
    
153
    if (j_eng.s.error)  // we need to check why the loop ended.
154
                        // Did we get to the end of JSON, or came upon error.
155
    {
156
       signal_error_in_JSON()
157
    }
158
159
160
  Parts of JSON can be quickly skipped. If we are not interested
161
  in a particular key, we can just skip it with json_skip_key() call.
162
  Similarly json_skip_level() goes right to the end of an object
163
  or an array.
164
*/
165
166
167
/* These are JSON parser states that user can expect and handle.  */
168
enum json_states {
169
  JST_VALUE,       /* value found      */
170
  JST_KEY,         /* key found        */
171
  JST_OBJ_START,   /* object           */
172
  JST_OBJ_END,     /* object ended     */
173
  JST_ARRAY_START, /* array            */
174
  JST_ARRAY_END,   /* array ended      */
175
  NR_JSON_USER_STATES
176
};
177
178
179
enum json_value_types
180
{
181
  JSON_VALUE_UNINITIALIZED=0,
182
  JSON_VALUE_OBJECT=1,
183
  JSON_VALUE_ARRAY=2,
184
  JSON_VALUE_STRING=3,
185
  JSON_VALUE_NUMBER=4,
186
  JSON_VALUE_TRUE=5,
187
  JSON_VALUE_FALSE=6,
188
  JSON_VALUE_NULL=7
189
};
190
191
192
enum json_num_flags
193
{
194
  JSON_NUM_NEG=1,        /* Number is negative. */
195
  JSON_NUM_FRAC_PART=2,  /* The fractional part is not empty. */
196
  JSON_NUM_EXP=4,        /* The number has the 'e' part. */
197
};
198
199
200
typedef struct st_json_engine_t
201
{
202
  json_string_t s;  /* String to parse. */
203
  int sav_c_len;    /* Length of the current character.
204
                       Can be more than 1 for multibyte charsets */
205
206
  int state; /* The state of the parser. One of 'enum json_states'.
207
                It tells us what construction of JSON we've just read. */
208
209
  /* These values are only set after the json_read_value() call. */
210
  enum json_value_types value_type; /* type of the value.*/
211
  const uchar *value;      /* Points to the value. */
212
  const uchar *value_begin;/* Points to where the value starts in the JSON. */
213
  int value_escaped;       /* Flag telling if the string value has escaping.*/
214
  uint num_flags;  /* the details of the JSON_VALUE_NUMBER, is it negative,
215
                      or if it has the fractional part.
216
                      See the enum json_num_flags. */
217
218
  /*
219
    In most cases the 'value' and 'value_begin' are equal.
220
    They only differ if the value is a string constants. Then 'value_begin'
221
    points to the starting quotation mark, while the 'value' - to
222
    the first character of the string.
223
  */
224
225
  const uchar *value_end; /* Points to the next character after the value. */
226
  int value_len; /* The length of the value. Does not count quotations for */
227
                 /* string constants. */
228
229
  int stack[JSON_DEPTH_LIMIT]; /* Keeps the stack of nested JSON structures. */
230
  int stack_p;                 /* The 'stack' pointer. */
231
  volatile uchar *killed_ptr;
232
} json_engine_t;
233
234
235
int json_scan_start(json_engine_t *je,
236
                        CHARSET_INFO *i_cs, const uchar *str, const uchar *end);
237
int json_scan_next(json_engine_t *j);
238
239
240
/*
241
  json_read_keyname_chr() function assists parsing the name of an JSON key.
242
  It only can be called when the json_engine is in JST_KEY.
243
  The json_read_keyname_chr() reads one character of the name of the key,
244
  and puts it in j_eng.s.next_c.
245
  Typical usage is like this:
246
247
  if (j_eng.state == JST_KEY)
248
  {
249
    while (json_read_keyname_chr(&j) == 0)
250
    {
251
      //handle next character i.e. match it against the pattern
252
    }
253
  }
254
*/
255
256
int json_read_keyname_chr(json_engine_t *j);
257
258
259
/*
260
  Check if the name of the current JSON key matches
261
  the step of the path.
262
*/
263
int json_key_matches(json_engine_t *je, json_string_t *k);
264
265
266
/*
267
  json_read_value() function parses the JSON value syntax,
268
  so that we can handle the value of a key or an array item.
269
  It only returns meaningful result when the engine is in
270
  the JST_VALUE state.
271
272
  Typical usage is like this:
273
274
  if (j_eng.state ==  JST_VALUE)
275
  {
276
    json_read_value(&j_eng);
277
    switch(j_eng.value_type)
278
    {
279
      case JSON_VALUE_STRING:
280
        // get the string
281
        str= j_eng.value;
282
        str_length= j_eng.value_len;
283
      case JSON_VALUE_NUMBER:
284
        // get the number
285
      ... etc
286
    }
287
*/
288
int json_read_value(json_engine_t *j);
289
290
291
/*
292
  json_skip_key() makes parser skip the content of the current
293
  JSON key quickly.
294
  It can be called only when the json_engine state is JST_KEY.
295
  Typical usage is:
296
297
  if (j_eng.state == JST_KEY)
298
  {
299
    if (key_does_not_match(j_eng))
300
      json_skip_key(j_eng);
301
  }
302
*/
303
304
int json_skip_key(json_engine_t *j);
305
306
307
typedef const int *json_level_t;
308
309
/*
310
  json_skip_to_level() makes parser quickly get out of nested
311
  loops and arrays. It is used when we're not interested in what is
312
  there in the rest of these structures.
313
  The 'level' should be remembered in advance.
314
        json_level_t level= json_get_level(j);
315
        .... // getting into the nested JSON structures
316
        json_skip_to_level(j, level);
317
*/
318
#define json_get_level(j) (j->stack_p)
319
320
int json_skip_to_level(json_engine_t *j, int level);
321
322
/*
323
  json_skip_level() works as above with just current structure.
324
  So it gets to the end of the current JSON array or object.
325
*/
326
#define json_skip_level(json_engine) \
327
2.27k
  json_skip_to_level((json_engine), (json_engine)->stack_p)
328
329
330
/*
331
  works as json_skip_level() but also counts items on the current
332
  level skipped.
333
*/
334
int json_skip_level_and_count(json_engine_t *j, int *n_items_skipped);
335
336
0
#define json_skip_array_item json_skip_key
337
338
/*
339
  Checks if the current value is of scalar type -
340
  not an OBJECT nor ARRAY.
341
*/
342
13.8k
#define json_value_scalar(je)  ((je)->value_type > JSON_VALUE_ARRAY)
343
344
345
/*
346
  Look for the JSON PATH in the json string.
347
  Function can be called several times with same JSON/PATH to
348
  find multiple matches.
349
  On the first call, the json_engine_t parameter should be
350
  initialized with the JSON string, and the json_path_t with the JSON path
351
  appropriately. The 'p_cur_step' should point at the first
352
  step of the path.
353
  The 'array_counters' is the array of JSON_DEPTH_LIMIT size.
354
  It stores the array counters of the parsed JSON.
355
  If function returns 0, it means it found the match. The position of
356
  the match is je->s.c_str. Then we can call the json_find_path()
357
  with same engine/path/p_cur_step to get the next match.
358
  Non-zero return means no matches found.
359
  Check je->s.error to see if there was an error in JSON.
360
*/
361
int json_find_path(json_engine_t *je,
362
                   json_path_t *p, json_path_step_t **p_cur_step,
363
                   int *array_counters);
364
365
366
typedef struct st_json_find_paths_t
367
{
368
  uint n_paths;
369
  json_path_t *paths;
370
  uint cur_depth;
371
  uint *path_depths;
372
  int array_counters[JSON_DEPTH_LIMIT];
373
} json_find_paths_t;
374
375
376
int json_find_paths_first(json_engine_t *je, json_find_paths_t *state,
377
                          uint n_paths, json_path_t *paths, uint *path_depths);
378
int json_find_paths_next(json_engine_t *je, json_find_paths_t *state);
379
380
381
0
#define JSON_ERROR_OUT_OF_SPACE  (-1)
382
0
#define JSON_ERROR_ILLEGAL_SYMBOL (-2)
383
384
/*
385
  Convert JSON string constant into ordinary string constant
386
  which can involve unpacking json escapes and changing character set.
387
  Returns negative integer in the case of an error,
388
  the length of the result otherwise.
389
*/
390
int json_unescape(CHARSET_INFO *json_cs,
391
                  const uchar *json_str, const uchar *json_end,
392
                  CHARSET_INFO *res_cs,
393
                  uchar *res, uchar *res_end);
394
395
/*
396
  Convert a string constant into JSON string constant.
397
  This can involve appropriate escaping and changing the character set.
398
  Returns the length of the result on success,
399
  on error returns a negative error code.
400
  Some error codes:
401
    JSON_ERROR_OUT_OF_SPACE    Not enough space in the provided buffer
402
    JSON_ERROR_ILLEGAL_SYMBOL  Source symbol cannot be represented in JSON
403
*/
404
int json_escape(CHARSET_INFO *str_cs, const uchar *str, const uchar *str_end,
405
                CHARSET_INFO *json_cs, uchar *json, uchar *json_end);
406
407
408
/*
409
  Appends the ASCII string to the json with the charset conversion.
410
*/
411
int json_append_ascii(CHARSET_INFO *json_cs,
412
                      uchar *json, uchar *json_end,
413
                      const uchar *ascii, const uchar *ascii_end);
414
415
416
/*
417
  Scan the JSON and return paths met one-by-one.
418
     json_get_path_start(&p)
419
     while (json_get_path_next(&p))
420
     {
421
       handle_the_next_path();
422
     }
423
*/
424
425
int json_get_path_start(json_engine_t *je, CHARSET_INFO *i_cs,
426
                        const uchar *str, const uchar *end,
427
                        json_path_t *p);
428
429
430
int json_get_path_next(json_engine_t *je, json_path_t *p);
431
432
int json_path_compare(const json_path_t *a, const json_path_t *b,
433
                      enum json_value_types vt, const int* array_size_counter);
434
435
int json_valid(const char *js, size_t js_len, CHARSET_INFO *cs);
436
437
int json_locate_key(const char *js, const char *js_end,
438
                    const char *kname,
439
                    const char **key_start, const char **key_end,
440
                    int *comma_pos);
441
442
int json_normalize(DYNAMIC_STRING *result,
443
                   const char *s, size_t size, CHARSET_INFO *cs);
444
445
int json_skip_array_and_count(json_engine_t *j, int* n_item);
446
447
inline static int json_scan_ended(json_engine_t *j)
448
0
{
449
0
  return (j->state == JST_ARRAY_END && j->stack_p == 0);
450
0
}
Unexecuted instantiation: fuzz_json.c:json_scan_ended
Unexecuted instantiation: json_lib.c:json_scan_ended
451
452
#ifdef  __cplusplus
453
}
454
#endif
455
456
#endif /* JSON_LIB_INCLUDED */