1 | /* |
2 | * Copyright © 2021 Benjamin Otte |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2.1 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
16 | * |
17 | * Authors: Benjamin Otte <otte@gnome.org> |
18 | */ |
19 | |
20 | |
21 | #include "config.h" |
22 | |
23 | #include "gtkjsonparserprivate.h" |
24 | #include <stdlib.h> |
25 | #include <errno.h> |
26 | |
27 | typedef struct _GtkJsonBlock GtkJsonBlock; |
28 | |
29 | typedef enum { |
30 | GTK_JSON_BLOCK_TOPLEVEL, |
31 | GTK_JSON_BLOCK_OBJECT, |
32 | GTK_JSON_BLOCK_ARRAY, |
33 | } GtkJsonBlockType; |
34 | |
35 | struct _GtkJsonBlock |
36 | { |
37 | GtkJsonBlockType type; |
38 | const guchar *value; /* start of current value to be consumed by external code */ |
39 | const guchar *member_name; /* name of current value, only used for object types */ |
40 | gsize index; /* index of the current element */ |
41 | }; |
42 | |
43 | struct _GtkJsonParser |
44 | { |
45 | GBytes *bytes; |
46 | const guchar *reader; /* current read head, pointing as far as we've read */ |
47 | const guchar *start; /* pointer at start of data, after optional BOM */ |
48 | const guchar *end; /* pointer after end of data we're reading */ |
49 | |
50 | GError *error; /* if an error has happened, it's stored here. Errors aren't recoverable. */ |
51 | const guchar *error_start; /* start of error location */ |
52 | const guchar *error_end; /* end of error location */ |
53 | |
54 | GtkJsonBlock *block; /* current block */ |
55 | GtkJsonBlock *blocks; /* blocks array */ |
56 | GtkJsonBlock *blocks_end; /* blocks array */ |
57 | GtkJsonBlock blocks_preallocated[128]; /* preallocated */ |
58 | }; |
59 | |
60 | typedef enum { |
61 | WHITESPACE = (1 << 4), |
62 | NEWLINE = (1 << 5), |
63 | STRING_ELEMENT = (1 << 6), |
64 | STRING_MARKER = (1 << 7), |
65 | } JsonCharacterType; |
66 | |
67 | #define JSON_CHARACTER_NODE_MASK ((1 << 4) - 1) |
68 | |
69 | static const guchar json_character_table[256] = { |
70 | ['\t'] = WHITESPACE, |
71 | ['\r'] = WHITESPACE | NEWLINE, |
72 | ['\n'] = WHITESPACE | NEWLINE, |
73 | [' '] = WHITESPACE | STRING_ELEMENT, |
74 | ['!'] = STRING_ELEMENT, |
75 | ['"'] = GTK_JSON_STRING | STRING_MARKER, |
76 | ['#'] = STRING_ELEMENT, |
77 | ['$'] = STRING_ELEMENT, |
78 | ['%'] = STRING_ELEMENT, |
79 | ['&'] = STRING_ELEMENT, |
80 | ['\''] = STRING_ELEMENT, |
81 | ['('] = STRING_ELEMENT, |
82 | [')'] = STRING_ELEMENT, |
83 | ['*'] = STRING_ELEMENT, |
84 | ['+'] = STRING_ELEMENT, |
85 | [','] = STRING_ELEMENT, |
86 | ['-'] = GTK_JSON_NUMBER | STRING_ELEMENT, |
87 | ['.'] = STRING_ELEMENT, |
88 | ['/'] = STRING_ELEMENT, |
89 | ['0'] = GTK_JSON_NUMBER | STRING_ELEMENT, |
90 | ['1'] = GTK_JSON_NUMBER | STRING_ELEMENT, |
91 | ['2'] = GTK_JSON_NUMBER | STRING_ELEMENT, |
92 | ['3'] = GTK_JSON_NUMBER | STRING_ELEMENT, |
93 | ['4'] = GTK_JSON_NUMBER | STRING_ELEMENT, |
94 | ['5'] = GTK_JSON_NUMBER | STRING_ELEMENT, |
95 | ['6'] = GTK_JSON_NUMBER | STRING_ELEMENT, |
96 | ['7'] = GTK_JSON_NUMBER | STRING_ELEMENT, |
97 | ['8'] = GTK_JSON_NUMBER | STRING_ELEMENT, |
98 | ['9'] = GTK_JSON_NUMBER | STRING_ELEMENT, |
99 | [':'] = STRING_ELEMENT, |
100 | [';'] = STRING_ELEMENT, |
101 | ['<'] = STRING_ELEMENT, |
102 | ['='] = STRING_ELEMENT, |
103 | ['>'] = STRING_ELEMENT, |
104 | ['?'] = STRING_ELEMENT, |
105 | ['@'] = STRING_ELEMENT, |
106 | ['A'] = STRING_ELEMENT, |
107 | ['B'] = STRING_ELEMENT, |
108 | ['C'] = STRING_ELEMENT, |
109 | ['D'] = STRING_ELEMENT, |
110 | ['E'] = STRING_ELEMENT, |
111 | ['F'] = STRING_ELEMENT, |
112 | ['G'] = STRING_ELEMENT, |
113 | ['H'] = STRING_ELEMENT, |
114 | ['I'] = STRING_ELEMENT, |
115 | ['J'] = STRING_ELEMENT, |
116 | ['K'] = STRING_ELEMENT, |
117 | ['L'] = STRING_ELEMENT, |
118 | ['M'] = STRING_ELEMENT, |
119 | ['N'] = STRING_ELEMENT, |
120 | ['O'] = STRING_ELEMENT, |
121 | ['P'] = STRING_ELEMENT, |
122 | ['Q'] = STRING_ELEMENT, |
123 | ['R'] = STRING_ELEMENT, |
124 | ['S'] = STRING_ELEMENT, |
125 | ['T'] = STRING_ELEMENT, |
126 | ['U'] = STRING_ELEMENT, |
127 | ['V'] = STRING_ELEMENT, |
128 | ['W'] = STRING_ELEMENT, |
129 | ['X'] = STRING_ELEMENT, |
130 | ['Y'] = STRING_ELEMENT, |
131 | ['Z'] = STRING_ELEMENT, |
132 | ['['] = GTK_JSON_ARRAY | STRING_ELEMENT, |
133 | ['\\'] = STRING_MARKER, |
134 | [']'] = STRING_ELEMENT, |
135 | ['^'] = STRING_ELEMENT, |
136 | ['_'] = STRING_ELEMENT, |
137 | ['`'] = STRING_ELEMENT, |
138 | ['a'] = STRING_ELEMENT, |
139 | ['b'] = STRING_ELEMENT, |
140 | ['c'] = STRING_ELEMENT, |
141 | ['d'] = STRING_ELEMENT, |
142 | ['e'] = STRING_ELEMENT, |
143 | ['f'] = GTK_JSON_BOOLEAN | STRING_ELEMENT, |
144 | ['g'] = STRING_ELEMENT, |
145 | ['h'] = STRING_ELEMENT, |
146 | ['i'] = STRING_ELEMENT, |
147 | ['j'] = STRING_ELEMENT, |
148 | ['k'] = STRING_ELEMENT, |
149 | ['l'] = STRING_ELEMENT, |
150 | ['m'] = STRING_ELEMENT, |
151 | ['n'] = GTK_JSON_NULL | STRING_ELEMENT, |
152 | ['o'] = STRING_ELEMENT, |
153 | ['p'] = STRING_ELEMENT, |
154 | ['q'] = STRING_ELEMENT, |
155 | ['r'] = STRING_ELEMENT, |
156 | ['s'] = STRING_ELEMENT, |
157 | ['t'] = GTK_JSON_BOOLEAN | STRING_ELEMENT, |
158 | ['u'] = STRING_ELEMENT, |
159 | ['v'] = STRING_ELEMENT, |
160 | ['w'] = STRING_ELEMENT, |
161 | ['x'] = STRING_ELEMENT, |
162 | ['y'] = STRING_ELEMENT, |
163 | ['z'] = STRING_ELEMENT, |
164 | ['{'] = GTK_JSON_OBJECT | STRING_ELEMENT, |
165 | ['|'] = STRING_ELEMENT, |
166 | ['}'] = STRING_ELEMENT, |
167 | ['~'] = STRING_ELEMENT, |
168 | [127] = STRING_ELEMENT, |
169 | }; |
170 | |
171 | static const guchar * |
172 | json_skip_characters (const guchar *start, |
173 | const guchar *end, |
174 | JsonCharacterType type) |
175 | { |
176 | const guchar *s; |
177 | |
178 | for (s = start; s < end; s++) |
179 | { |
180 | if (!(json_character_table[*s] & type)) |
181 | break; |
182 | } |
183 | return s; |
184 | } |
185 | |
186 | static const guchar * |
187 | json_skip_characters_until (const guchar *start, |
188 | const guchar *end, |
189 | JsonCharacterType type) |
190 | { |
191 | const guchar *s; |
192 | |
193 | for (s = start; s < end; s++) |
194 | { |
195 | if (json_character_table[*s] & type) |
196 | break; |
197 | } |
198 | return s; |
199 | } |
200 | |
201 | static const guchar * |
202 | json_find_character (const guchar *start, |
203 | JsonCharacterType type) |
204 | { |
205 | const guchar *s; |
206 | |
207 | for (s = start; ; s++) |
208 | { |
209 | if ((json_character_table[*s] & type)) |
210 | break; |
211 | } |
212 | return s; |
213 | } |
214 | |
215 | GQuark |
216 | gtk_json_error_quark (void) |
217 | { |
218 | return g_quark_from_static_string (string: "gtk-json-error-quark" ); |
219 | } |
220 | |
221 | static void |
222 | gtk_json_parser_take_error (GtkJsonParser *self, |
223 | const guchar *start_location, |
224 | const guchar *end_location, |
225 | GError *error) |
226 | { |
227 | g_assert (start_location <= end_location); |
228 | g_assert (self->start <= start_location); |
229 | g_assert (end_location <= self->end); |
230 | |
231 | if (self->error) |
232 | { |
233 | g_error_free (error); |
234 | return; |
235 | } |
236 | |
237 | self->error = error; |
238 | self->error_start = start_location; |
239 | self->error_end = end_location; |
240 | } |
241 | |
242 | static void |
243 | gtk_json_parser_syntax_error_at (GtkJsonParser *self, |
244 | const guchar *error_start, |
245 | const guchar *error_end, |
246 | const char *format, |
247 | ...) G_GNUC_PRINTF(4, 5); |
248 | static void |
249 | gtk_json_parser_syntax_error_at (GtkJsonParser *self, |
250 | const guchar *error_start, |
251 | const guchar *error_end, |
252 | const char *format, |
253 | ...) |
254 | { |
255 | va_list args; |
256 | |
257 | if (self->error) |
258 | return; |
259 | |
260 | va_start (args, format); |
261 | gtk_json_parser_take_error (self, |
262 | start_location: error_start, |
263 | end_location: error_end, |
264 | error: g_error_new_valist (GTK_JSON_ERROR, |
265 | code: GTK_JSON_ERROR_SYNTAX, |
266 | format, args)); |
267 | va_end (args); |
268 | } |
269 | |
270 | static void |
271 | gtk_json_parser_syntax_error (GtkJsonParser *self, |
272 | const char *format, |
273 | ...) G_GNUC_PRINTF(2, 3); |
274 | static void |
275 | gtk_json_parser_syntax_error (GtkJsonParser *self, |
276 | const char *format, |
277 | ...) |
278 | { |
279 | va_list args; |
280 | const guchar *error_end; |
281 | |
282 | if (self->error) |
283 | return; |
284 | |
285 | va_start (args, format); |
286 | for (error_end = self->reader; |
287 | error_end < self->end && g_ascii_isalnum (*error_end); |
288 | error_end++) |
289 | ; |
290 | if (error_end == self->reader && |
291 | g_utf8_get_char_validated (p: (const char *) error_end, max_len: self->end - error_end) < (gunichar) -2) |
292 | { |
293 | error_end = (const guchar *) g_utf8_next_char (error_end); |
294 | } |
295 | |
296 | gtk_json_parser_take_error (self, |
297 | start_location: self->reader, |
298 | end_location: error_end, |
299 | error: g_error_new_valist (GTK_JSON_ERROR, |
300 | code: GTK_JSON_ERROR_SYNTAX, |
301 | format, args)); |
302 | va_end (args); |
303 | } |
304 | |
305 | static void |
306 | gtk_json_parser_type_error (GtkJsonParser *self, |
307 | const char *format, |
308 | ...) G_GNUC_PRINTF(2, 3); |
309 | static void |
310 | gtk_json_parser_type_error (GtkJsonParser *self, |
311 | const char *format, |
312 | ...) |
313 | { |
314 | const guchar *start_location; |
315 | va_list args; |
316 | |
317 | if (self->error) |
318 | return; |
319 | |
320 | if (self->block->value) |
321 | start_location = self->block->value; |
322 | else if (self->block != self->blocks) |
323 | start_location = self->block[-1].value; |
324 | else |
325 | start_location = self->start; |
326 | |
327 | va_start (args, format); |
328 | gtk_json_parser_take_error (self, |
329 | start_location, |
330 | end_location: self->reader, |
331 | error: g_error_new_valist (GTK_JSON_ERROR, |
332 | code: GTK_JSON_ERROR_TYPE, |
333 | format, args)); |
334 | va_end (args); |
335 | } |
336 | |
337 | void |
338 | gtk_json_parser_value_error (GtkJsonParser *self, |
339 | const char *format, |
340 | ...) |
341 | { |
342 | const guchar *start_location; |
343 | va_list args; |
344 | |
345 | if (self->error) |
346 | return; |
347 | |
348 | if (self->block->value) |
349 | start_location = self->block->value; |
350 | else if (self->block != self->blocks) |
351 | start_location = self->block[-1].value; |
352 | else |
353 | start_location = self->start; |
354 | |
355 | va_start (args, format); |
356 | gtk_json_parser_take_error (self, |
357 | start_location, |
358 | end_location: self->reader, |
359 | error: g_error_new_valist (GTK_JSON_ERROR, |
360 | code: GTK_JSON_ERROR_VALUE, |
361 | format, args)); |
362 | va_end (args); |
363 | } |
364 | |
365 | void |
366 | gtk_json_parser_schema_error (GtkJsonParser *self, |
367 | const char *format, |
368 | ...) |
369 | { |
370 | const guchar *start_location; |
371 | va_list args; |
372 | |
373 | if (self->error) |
374 | return; |
375 | |
376 | if (self->block->member_name) |
377 | start_location = self->block->member_name; |
378 | if (self->block->value) |
379 | start_location = self->block->value; |
380 | else if (self->block != self->blocks) |
381 | start_location = self->block[-1].value; |
382 | else |
383 | start_location = self->start; |
384 | |
385 | va_start (args, format); |
386 | gtk_json_parser_take_error (self, |
387 | start_location, |
388 | end_location: self->reader, |
389 | error: g_error_new_valist (GTK_JSON_ERROR, |
390 | code: GTK_JSON_ERROR_SCHEMA, |
391 | format, args)); |
392 | va_end (args); |
393 | } |
394 | |
395 | static gboolean |
396 | gtk_json_parser_is_eof (GtkJsonParser *self) |
397 | { |
398 | return self->reader >= self->end; |
399 | } |
400 | |
401 | static gsize |
402 | gtk_json_parser_remaining (GtkJsonParser *self) |
403 | { |
404 | g_return_val_if_fail (self->reader <= self->end, 0); |
405 | |
406 | return self->end - self->reader; |
407 | } |
408 | |
409 | static void |
410 | gtk_json_parser_skip_bom (GtkJsonParser *self) |
411 | { |
412 | if (gtk_json_parser_remaining (self) < 3) |
413 | return; |
414 | |
415 | if (self->reader[0] == 0xEF && |
416 | self->reader[1] == 0xBB && |
417 | self->reader[2] == 0xBF) |
418 | self->reader += 3; |
419 | } |
420 | |
421 | static void |
422 | gtk_json_parser_skip_whitespace (GtkJsonParser *self) |
423 | { |
424 | self->reader = json_skip_characters (start: self->reader, end: self->end, type: WHITESPACE); |
425 | } |
426 | |
427 | static gboolean |
428 | gtk_json_parser_has_char (GtkJsonParser *self, |
429 | char c) |
430 | { |
431 | return gtk_json_parser_remaining (self) && *self->reader == c; |
432 | } |
433 | |
434 | static gboolean |
435 | gtk_json_parser_try_char (GtkJsonParser *self, |
436 | char c) |
437 | { |
438 | if (!gtk_json_parser_has_char (self, c)) |
439 | return FALSE; |
440 | |
441 | self->reader++; |
442 | return TRUE; |
443 | } |
444 | |
445 | static gboolean |
446 | gtk_json_parser_try_identifier_len (GtkJsonParser *self, |
447 | const char *ident, |
448 | gsize len) |
449 | { |
450 | if (gtk_json_parser_remaining (self) < len) |
451 | return FALSE; |
452 | |
453 | if (memcmp (s1: self->reader, s2: ident, n: len) != 0) |
454 | return FALSE; |
455 | |
456 | self->reader += len; |
457 | return TRUE; |
458 | } |
459 | |
460 | #define gtk_json_parser_try_identifier(parser, ident) gtk_json_parser_try_identifier_len(parser, ident, strlen(ident)) |
461 | |
462 | /* |
463 | * decode_utf16_surrogate_pair: |
464 | * @first: the first UTF-16 code point |
465 | * @second: the second UTF-16 code point |
466 | * |
467 | * Decodes a surrogate pair of UTF-16 code points into the equivalent |
468 | * Unicode code point. |
469 | * |
470 | * If the code points are not valid, 0 is returned. |
471 | * |
472 | * Returns: the Unicode code point equivalent to the surrogate pair |
473 | */ |
474 | static inline gunichar |
475 | decode_utf16_surrogate_pair (gunichar first, |
476 | gunichar second) |
477 | { |
478 | if (0xd800 > first || first > 0xdbff || |
479 | 0xdc00 > second || second > 0xdfff) |
480 | return 0; |
481 | |
482 | return 0x10000 |
483 | | (first & 0x3ff) << 10 |
484 | | (second & 0x3ff); |
485 | } |
486 | |
487 | static gsize |
488 | gtk_json_unescape_char (const guchar *json_escape, |
489 | char out_data[6], |
490 | gsize *out_len) |
491 | { |
492 | switch (json_escape[1]) |
493 | { |
494 | case '"': |
495 | case '\\': |
496 | case '/': |
497 | out_data[0] = json_escape[1]; |
498 | *out_len = 1; |
499 | return 2; |
500 | case 'b': |
501 | out_data[0] = '\b'; |
502 | *out_len = 1; |
503 | return 2; |
504 | case 'f': |
505 | out_data[0] = '\f'; |
506 | *out_len = 1; |
507 | return 2; |
508 | case 'n': |
509 | out_data[0] = '\n'; |
510 | *out_len = 1; |
511 | return 2; |
512 | case 'r': |
513 | out_data[0] = '\r'; |
514 | *out_len = 1; |
515 | return 2; |
516 | case 't': |
517 | out_data[0] = '\t'; |
518 | *out_len = 1; |
519 | return 2; |
520 | case 'u': |
521 | { |
522 | gunichar unichar = (g_ascii_xdigit_value (c: json_escape[2]) << 12) | |
523 | (g_ascii_xdigit_value (c: json_escape[3]) << 8) | |
524 | (g_ascii_xdigit_value (c: json_escape[4]) << 4) | |
525 | (g_ascii_xdigit_value (c: json_escape[5])); |
526 | gsize result = 6; |
527 | |
528 | /* resolve UTF-16 surrogates for Unicode characters not in the BMP, |
529 | * as per ECMA 404, § 9, "String" |
530 | */ |
531 | if (g_unichar_type (c: unichar) == G_UNICODE_SURROGATE) |
532 | { |
533 | unichar = decode_utf16_surrogate_pair (first: unichar, |
534 | second: (g_ascii_xdigit_value (c: json_escape[8]) << 12) | |
535 | (g_ascii_xdigit_value (c: json_escape[9]) << 8) | |
536 | (g_ascii_xdigit_value (c: json_escape[10]) << 4) | |
537 | (g_ascii_xdigit_value (c: json_escape[11]))); |
538 | result += 6; |
539 | } |
540 | *out_len = g_unichar_to_utf8 (c: unichar, outbuf: out_data); |
541 | return result; |
542 | } |
543 | default: |
544 | g_assert_not_reached (); |
545 | return 0; |
546 | } |
547 | } |
548 | |
549 | typedef struct _JsonStringIter JsonStringIter; |
550 | struct _JsonStringIter |
551 | { |
552 | char buf[6]; |
553 | const guchar *s; |
554 | const guchar *next; |
555 | }; |
556 | |
557 | static gsize |
558 | json_string_iter_next (JsonStringIter *iter) |
559 | { |
560 | gsize len; |
561 | |
562 | iter->s = iter->next; |
563 | iter->next = json_find_character (start: iter->s, type: STRING_MARKER); |
564 | if (iter->next != iter->s) |
565 | return iter->next - iter->s; |
566 | if (*iter->next == '"') |
567 | return 0; |
568 | iter->next += gtk_json_unescape_char (json_escape: iter->next, out_data: iter->buf, out_len: &len); |
569 | iter->s = (const guchar *) iter->buf; |
570 | return len; |
571 | } |
572 | |
573 | /* The escaped string MUST be valid json, so it must begin |
574 | * with " and end with " and must not contain any invalid |
575 | * escape codes. |
576 | * This function is meant to be fast |
577 | */ |
578 | static gsize |
579 | json_string_iter_init (JsonStringIter *iter, |
580 | const guchar *string) |
581 | { |
582 | g_assert (*string == '"'); |
583 | |
584 | iter->next = string + 1; |
585 | |
586 | return json_string_iter_next (iter); |
587 | } |
588 | |
589 | static gboolean |
590 | json_string_iter_has_next (JsonStringIter *iter) |
591 | { |
592 | return *iter->next != '"'; |
593 | } |
594 | |
595 | static const char * |
596 | json_string_iter_get (JsonStringIter *iter) |
597 | { |
598 | return (const char *) iter->s; |
599 | } |
600 | |
601 | /* The escaped string MUST be valid json, so it must begin |
602 | * with " and end with " and must not contain any invalid |
603 | * escape codes. |
604 | * This function is meant to be fast |
605 | */ |
606 | static char * |
607 | gtk_json_unescape_string (const guchar *escaped) |
608 | { |
609 | JsonStringIter iter; |
610 | GString *string; |
611 | gsize len; |
612 | |
613 | len = json_string_iter_init (iter: &iter, string: escaped); |
614 | string = NULL; |
615 | |
616 | if (!json_string_iter_has_next (iter: &iter)) |
617 | return g_strndup (str: json_string_iter_get (iter: &iter), n: len); |
618 | |
619 | string = g_string_new (NULL); |
620 | |
621 | do |
622 | { |
623 | g_string_append_len (string, val: json_string_iter_get (iter: &iter), len); |
624 | } |
625 | while ((len = json_string_iter_next (iter: &iter))); |
626 | |
627 | return g_string_free (string, FALSE); |
628 | } |
629 | |
630 | static gboolean |
631 | gtk_json_parser_parse_string (GtkJsonParser *self) |
632 | { |
633 | const guchar *start; |
634 | |
635 | start = self->reader; |
636 | |
637 | if (!gtk_json_parser_try_char (self, c: '"')) |
638 | { |
639 | gtk_json_parser_type_error (self, format: "Not a string" ); |
640 | return FALSE; |
641 | } |
642 | |
643 | self->reader = json_skip_characters (start: self->reader, end: self->end, type: STRING_ELEMENT); |
644 | |
645 | while (gtk_json_parser_remaining (self)) |
646 | { |
647 | if (*self->reader < 0x20) |
648 | { |
649 | if (*self->reader == '\r' || *self->reader == '\n') |
650 | gtk_json_parser_syntax_error (self, format: "Newlines in strings are not allowed" ); |
651 | else if (*self->reader == '\t') |
652 | gtk_json_parser_syntax_error (self, format: "Tabs not allowed in strings" ); |
653 | else |
654 | gtk_json_parser_syntax_error (self, format: "Disallowed control character in string literal" ); |
655 | return FALSE; |
656 | } |
657 | else if (*self->reader > 127) |
658 | { |
659 | gunichar c = g_utf8_get_char_validated (p: (const char *) self->reader, max_len: gtk_json_parser_remaining (self)); |
660 | if (c == (gunichar) -2 || c == (gunichar) -1) |
661 | { |
662 | gtk_json_parser_syntax_error (self, format: "Invalid UTF-8" ); |
663 | return FALSE; |
664 | } |
665 | self->reader = (const guchar *) g_utf8_next_char ((const char *) self->reader); |
666 | } |
667 | else if (*self->reader == '"') |
668 | { |
669 | self->reader++; |
670 | return TRUE; |
671 | } |
672 | else if (*self->reader == '\\') |
673 | { |
674 | if (gtk_json_parser_remaining (self) < 2) |
675 | { |
676 | self->reader = self->end; |
677 | goto end; |
678 | } |
679 | switch (self->reader[1]) |
680 | { |
681 | case '"': |
682 | case '\\': |
683 | case '/': |
684 | case 'b': |
685 | case 'f': |
686 | case 'n': |
687 | case 'r': |
688 | case 't': |
689 | break; |
690 | |
691 | case 'u': |
692 | /* lots of work necessary to validate the unicode escapes here */ |
693 | if (gtk_json_parser_remaining (self) < 6 || |
694 | !g_ascii_isxdigit (self->reader[2]) || |
695 | !g_ascii_isxdigit (self->reader[3]) || |
696 | !g_ascii_isxdigit (self->reader[4]) || |
697 | !g_ascii_isxdigit (self->reader[5])) |
698 | { |
699 | const guchar *end; |
700 | for (end = self->reader + 2; |
701 | end < self->reader + 6 && end < self->end; |
702 | end++) |
703 | { |
704 | if (!g_ascii_isxdigit (*end)) |
705 | break; |
706 | } |
707 | gtk_json_parser_syntax_error_at (self, error_start: self->reader, error_end: end, format: "Invalid Unicode escape sequence" ); |
708 | return FALSE; |
709 | } |
710 | else |
711 | { |
712 | gsize escape_size = 6; |
713 | gunichar unichar = (g_ascii_xdigit_value (c: self->reader[2]) << 12) | |
714 | (g_ascii_xdigit_value (c: self->reader[3]) << 8) | |
715 | (g_ascii_xdigit_value (c: self->reader[4]) << 4) | |
716 | (g_ascii_xdigit_value (c: self->reader[5])); |
717 | |
718 | /* resolve UTF-16 surrogates for Unicode characters not in the BMP, |
719 | * as per ECMA 404, § 9, "String" |
720 | */ |
721 | if (g_unichar_type (c: unichar) == G_UNICODE_SURROGATE) |
722 | { |
723 | if (gtk_json_parser_remaining (self) >= 12 && |
724 | self->reader[6] == '\\' && |
725 | self->reader[7] == 'u' && |
726 | g_ascii_isxdigit (self->reader[8]) && |
727 | g_ascii_isxdigit (self->reader[9]) && |
728 | g_ascii_isxdigit (self->reader[10]) && |
729 | g_ascii_isxdigit (self->reader[11])) |
730 | { |
731 | unichar = decode_utf16_surrogate_pair (first: unichar, |
732 | second: (g_ascii_xdigit_value (c: self->reader[8]) << 12) | |
733 | (g_ascii_xdigit_value (c: self->reader[9]) << 8) | |
734 | (g_ascii_xdigit_value (c: self->reader[10]) << 4) | |
735 | (g_ascii_xdigit_value (c: self->reader[11]))); |
736 | escape_size += 6; |
737 | } |
738 | else |
739 | { |
740 | unichar = 0; |
741 | } |
742 | |
743 | if (unichar == 0) |
744 | { |
745 | gtk_json_parser_syntax_error_at (self, error_start: self->reader, error_end: self->reader + escape_size, format: "Invalid UTF-16 surrogate pair" ); |
746 | return FALSE; |
747 | } |
748 | |
749 | self->reader += escape_size - 2; |
750 | } |
751 | } |
752 | break; |
753 | default: |
754 | if (g_utf8_get_char_validated (p: (const char *) self->reader + 1, max_len: self->end - self->reader - 1) < (gunichar) -2) |
755 | gtk_json_parser_syntax_error_at (self, error_start: self->reader, error_end: (const guchar *) g_utf8_next_char (self->reader + 1), format: "Unknown escape sequence" ); |
756 | else |
757 | gtk_json_parser_syntax_error_at (self, error_start: self->reader, error_end: self->reader + 1, format: "Unknown escape sequence" ); |
758 | return FALSE; |
759 | } |
760 | self->reader += 2; |
761 | } |
762 | |
763 | self->reader = json_skip_characters (start: self->reader, end: self->end, type: STRING_ELEMENT); |
764 | } |
765 | |
766 | end: |
767 | gtk_json_parser_syntax_error_at (self, error_start: start, error_end: self->reader, format: "Unterminated string literal" ); |
768 | return FALSE; |
769 | } |
770 | |
771 | static gboolean |
772 | gtk_json_parser_parse_number (GtkJsonParser *self) |
773 | { |
774 | const guchar *start = self->reader; |
775 | gboolean have_sign; |
776 | |
777 | /* sign */ |
778 | have_sign = gtk_json_parser_try_char (self, c: '-'); |
779 | |
780 | /* integer part */ |
781 | if (gtk_json_parser_try_char (self, c: '0')) |
782 | { |
783 | /* Technically, "01" in the JSON grammar would be 2 numbers: |
784 | * "0" followed by "1". |
785 | * Practically, nobody understands that it's 2 numbers, so we |
786 | * special-purpose an error message for it, because 2 numbers |
787 | * can never follow each other. |
788 | */ |
789 | if (!gtk_json_parser_is_eof (self) && |
790 | g_ascii_isdigit (*self->reader)) |
791 | { |
792 | do |
793 | { |
794 | self->reader++; |
795 | } |
796 | while (!gtk_json_parser_is_eof (self) && |
797 | g_ascii_isdigit (*self->reader)); |
798 | |
799 | gtk_json_parser_syntax_error_at (self, error_start: start, error_end: self->reader, format: "Numbers may not start with leading 0s" ); |
800 | return FALSE; |
801 | } |
802 | } |
803 | else |
804 | { |
805 | if (gtk_json_parser_is_eof (self) || |
806 | !g_ascii_isdigit (*self->reader)) |
807 | { |
808 | if (have_sign) |
809 | gtk_json_parser_syntax_error_at (self, error_start: start, error_end: self->reader, format: "Expected a number after '-' character" ); |
810 | else |
811 | gtk_json_parser_type_error (self, format: "Not a number" ); |
812 | return FALSE; |
813 | } |
814 | |
815 | self->reader++; |
816 | |
817 | while (!gtk_json_parser_is_eof (self) && g_ascii_isdigit (*self->reader)) |
818 | self->reader++; |
819 | } |
820 | |
821 | /* fractional part */ |
822 | if (gtk_json_parser_try_char (self, c: '.')) |
823 | { |
824 | if (!g_ascii_isdigit (*self->reader)) |
825 | { |
826 | gtk_json_parser_syntax_error_at (self, error_start: start, error_end: self->reader, format: "Expected a digit after '.'" ); |
827 | return FALSE; |
828 | } |
829 | |
830 | do |
831 | { |
832 | self->reader++; |
833 | } |
834 | while (!gtk_json_parser_is_eof (self) && g_ascii_isdigit (*self->reader)); |
835 | } |
836 | |
837 | /* exponent */ |
838 | if (gtk_json_parser_try_char (self, c: 'e') || |
839 | gtk_json_parser_try_char (self, c: 'E')) |
840 | { |
841 | if (!gtk_json_parser_try_char (self, c: '-')) |
842 | gtk_json_parser_try_char (self, c: '+'); |
843 | |
844 | if (!g_ascii_isdigit (*self->reader)) |
845 | { |
846 | gtk_json_parser_syntax_error_at (self, error_start: start, error_end: self->reader, format: "Expected a digit in exponent" ); |
847 | return FALSE; |
848 | } |
849 | |
850 | do |
851 | { |
852 | self->reader++; |
853 | } |
854 | while (!gtk_json_parser_is_eof (self) && g_ascii_isdigit (*self->reader)); |
855 | } |
856 | return TRUE; |
857 | } |
858 | |
859 | static gboolean |
860 | gtk_json_parser_parse_value (GtkJsonParser *self) |
861 | { |
862 | if (gtk_json_parser_is_eof (self)) |
863 | { |
864 | gtk_json_parser_syntax_error (self, format: "Unexpected end of document" ); |
865 | return FALSE; |
866 | } |
867 | |
868 | switch (json_character_table[*self->block->value] & JSON_CHARACTER_NODE_MASK) |
869 | { |
870 | case GTK_JSON_STRING: |
871 | return gtk_json_parser_parse_string (self); |
872 | |
873 | case GTK_JSON_NUMBER: |
874 | return gtk_json_parser_parse_number (self); |
875 | |
876 | case GTK_JSON_NULL: |
877 | if (gtk_json_parser_try_identifier (self, "null" )) |
878 | return TRUE; |
879 | break; |
880 | |
881 | case GTK_JSON_BOOLEAN: |
882 | if (gtk_json_parser_try_identifier (self, "true" ) || |
883 | gtk_json_parser_try_identifier (self, "false" )) |
884 | return TRUE; |
885 | break; |
886 | |
887 | case GTK_JSON_OBJECT: |
888 | case GTK_JSON_ARRAY: |
889 | /* don't preparse objects */ |
890 | return TRUE; |
891 | |
892 | default: |
893 | break; |
894 | } |
895 | |
896 | if (gtk_json_parser_remaining (self) >= 2 && |
897 | (self->block->value[0] == '.' || self->block->value[0] == '+') && |
898 | g_ascii_isdigit (self->block->value[1])) |
899 | { |
900 | const guchar *end = self->block->value + 2; |
901 | while (end < self->end && g_ascii_isalnum (*end)) |
902 | end++; |
903 | gtk_json_parser_syntax_error_at (self, error_start: self->block->value, error_end: end, format: "Numbers may not start with '%c'" , *self->block->value); |
904 | } |
905 | else if (*self->reader == 0) |
906 | gtk_json_parser_syntax_error (self, format: "Unexpected nul byte in document" ); |
907 | else |
908 | gtk_json_parser_syntax_error (self, format: "Expected a value" ); |
909 | return FALSE; |
910 | } |
911 | |
912 | static void |
913 | gtk_json_parser_push_block (GtkJsonParser *self, |
914 | GtkJsonBlockType type) |
915 | { |
916 | self->block++; |
917 | if (self->block == self->blocks_end) |
918 | { |
919 | gsize old_size = self->blocks_end - self->blocks; |
920 | gsize new_size = old_size + 128; |
921 | |
922 | if (self->blocks == self->blocks_preallocated) |
923 | { |
924 | self->blocks = g_new (GtkJsonBlock, new_size); |
925 | memcpy (dest: self->blocks, src: self->blocks_preallocated, n: sizeof (GtkJsonBlock) * G_N_ELEMENTS (self->blocks_preallocated)); |
926 | } |
927 | else |
928 | { |
929 | self->blocks = g_renew (GtkJsonBlock, self->blocks, new_size); |
930 | } |
931 | self->blocks_end = self->blocks + new_size; |
932 | self->block = self->blocks + old_size; |
933 | } |
934 | |
935 | self->block->type = type; |
936 | self->block->member_name = 0; |
937 | self->block->value = 0; |
938 | self->block->index = 0; |
939 | } |
940 | |
941 | static void |
942 | gtk_json_parser_pop_block (GtkJsonParser *self) |
943 | { |
944 | g_assert (self->block > self->blocks); |
945 | self->block--; |
946 | } |
947 | |
948 | GtkJsonParser * |
949 | gtk_json_parser_new_for_string (const char *string, |
950 | gssize size) |
951 | { |
952 | GtkJsonParser *self; |
953 | GBytes *bytes; |
954 | |
955 | bytes = g_bytes_new (data: string, size: size >= 0 ? size : strlen (s: string)); |
956 | |
957 | self = gtk_json_parser_new_for_bytes (bytes); |
958 | |
959 | g_bytes_unref (bytes); |
960 | |
961 | return self; |
962 | } |
963 | |
964 | GtkJsonParser * |
965 | gtk_json_parser_new_for_bytes (GBytes *bytes) |
966 | { |
967 | GtkJsonParser *self; |
968 | gsize size; |
969 | |
970 | g_return_val_if_fail (bytes != NULL, NULL); |
971 | |
972 | self = g_slice_new0 (GtkJsonParser); |
973 | |
974 | self->bytes = g_bytes_ref (bytes); |
975 | self->reader = g_bytes_get_data (bytes, size: &size); |
976 | self->end = self->reader + size; |
977 | |
978 | self->blocks = self->blocks_preallocated; |
979 | self->blocks_end = self->blocks + G_N_ELEMENTS (self->blocks_preallocated); |
980 | self->block = self->blocks; |
981 | self->block->type = GTK_JSON_BLOCK_TOPLEVEL; |
982 | |
983 | gtk_json_parser_skip_bom (self); |
984 | self->start = self->reader; |
985 | gtk_json_parser_rewind (self); |
986 | |
987 | return self; |
988 | } |
989 | |
990 | void |
991 | gtk_json_parser_free (GtkJsonParser *self) |
992 | { |
993 | if (self == NULL) |
994 | return; |
995 | |
996 | g_bytes_unref (bytes: self->bytes); |
997 | |
998 | if (self->blocks != self->blocks_preallocated) |
999 | g_free (mem: self->blocks); |
1000 | |
1001 | if (self->error) |
1002 | g_error_free (error: self->error); |
1003 | |
1004 | g_slice_free (GtkJsonParser, self); |
1005 | } |
1006 | |
1007 | static gboolean |
1008 | gtk_json_parser_skip_block (GtkJsonParser *self) |
1009 | { |
1010 | gsize depth; |
1011 | |
1012 | if (self->reader != self->block->value) |
1013 | return TRUE; |
1014 | |
1015 | depth = gtk_json_parser_get_depth (self); |
1016 | while (TRUE) |
1017 | { |
1018 | if (*self->reader == '{') |
1019 | { |
1020 | if (!gtk_json_parser_start_object (self)) |
1021 | return FALSE; |
1022 | } |
1023 | else if (*self->reader == '[') |
1024 | { |
1025 | if (!gtk_json_parser_start_array (self)) |
1026 | return FALSE; |
1027 | } |
1028 | |
1029 | while (self->reader != self->block->value) |
1030 | { |
1031 | /* This should never be reentrant to this function or we might |
1032 | * loop causing stack overflow */ |
1033 | if (!gtk_json_parser_next (self)) |
1034 | { |
1035 | if (!gtk_json_parser_end (self)) |
1036 | return FALSE; |
1037 | if (depth >= gtk_json_parser_get_depth (self)) |
1038 | return TRUE; |
1039 | } |
1040 | } |
1041 | } |
1042 | |
1043 | return TRUE; |
1044 | } |
1045 | |
1046 | gboolean |
1047 | gtk_json_parser_next (GtkJsonParser *self) |
1048 | { |
1049 | if (self->error) |
1050 | return FALSE; |
1051 | |
1052 | if (self->block->value == NULL) |
1053 | return FALSE; |
1054 | |
1055 | if (!gtk_json_parser_skip_block (self)) |
1056 | { |
1057 | g_assert (self->error); |
1058 | return FALSE; |
1059 | } |
1060 | |
1061 | switch (self->block->type) |
1062 | { |
1063 | case GTK_JSON_BLOCK_TOPLEVEL: |
1064 | gtk_json_parser_skip_whitespace (self); |
1065 | if (gtk_json_parser_is_eof (self)) |
1066 | { |
1067 | self->block->value = NULL; |
1068 | } |
1069 | else if (*self->reader == 0) |
1070 | { |
1071 | gtk_json_parser_syntax_error (self, format: "Unexpected nul byte in document" ); |
1072 | } |
1073 | else |
1074 | { |
1075 | gtk_json_parser_syntax_error_at (self, error_start: self->reader, error_end: self->end, format: "Data at end of document" ); |
1076 | } |
1077 | return FALSE; |
1078 | |
1079 | case GTK_JSON_BLOCK_OBJECT: |
1080 | gtk_json_parser_skip_whitespace (self); |
1081 | if (gtk_json_parser_is_eof (self)) |
1082 | { |
1083 | gtk_json_parser_syntax_error_at (self, |
1084 | error_start: self->block[-1].value, |
1085 | error_end: self->reader, |
1086 | format: "Unterminated object" ); |
1087 | self->block->member_name = NULL; |
1088 | self->block->value = NULL; |
1089 | } |
1090 | if (gtk_json_parser_has_char (self, c: '}')) |
1091 | { |
1092 | self->block->member_name = NULL; |
1093 | self->block->value = NULL; |
1094 | return FALSE; |
1095 | } |
1096 | if (!gtk_json_parser_try_char (self, c: ',')) |
1097 | { |
1098 | gtk_json_parser_syntax_error (self, format: "Expected a ',' to separate object members" ); |
1099 | return FALSE; |
1100 | } |
1101 | gtk_json_parser_skip_whitespace (self); |
1102 | if (!gtk_json_parser_has_char (self, c: '"')) |
1103 | { |
1104 | gtk_json_parser_syntax_error (self, format: "Expected a string for object member name" ); |
1105 | return FALSE; |
1106 | } |
1107 | self->block->member_name = self->reader; |
1108 | |
1109 | if (!gtk_json_parser_parse_string (self)) |
1110 | return FALSE; |
1111 | gtk_json_parser_skip_whitespace (self); |
1112 | if (!gtk_json_parser_try_char (self, c: ':')) |
1113 | { |
1114 | gtk_json_parser_syntax_error (self, format: "Missing ':' after member name" ); |
1115 | return FALSE; |
1116 | } |
1117 | |
1118 | gtk_json_parser_skip_whitespace (self); |
1119 | self->block->value = self->reader; |
1120 | if (!gtk_json_parser_parse_value (self)) |
1121 | return FALSE; |
1122 | break; |
1123 | |
1124 | case GTK_JSON_BLOCK_ARRAY: |
1125 | gtk_json_parser_skip_whitespace (self); |
1126 | if (gtk_json_parser_is_eof (self)) |
1127 | { |
1128 | gtk_json_parser_syntax_error_at (self, |
1129 | error_start: self->block[-1].value, |
1130 | error_end: self->reader, |
1131 | format: "Unterminated array" ); |
1132 | self->block->member_name = NULL; |
1133 | self->block->value = NULL; |
1134 | } |
1135 | if (gtk_json_parser_has_char (self, c: ']')) |
1136 | { |
1137 | self->block->value = NULL; |
1138 | return FALSE; |
1139 | } |
1140 | |
1141 | if (!gtk_json_parser_try_char (self, c: ',')) |
1142 | { |
1143 | gtk_json_parser_syntax_error (self, format: "Expected a ',' to separate array members" ); |
1144 | return FALSE; |
1145 | } |
1146 | |
1147 | gtk_json_parser_skip_whitespace (self); |
1148 | self->block->value = self->reader; |
1149 | if (!gtk_json_parser_parse_value (self)) |
1150 | return FALSE; |
1151 | break; |
1152 | |
1153 | default: |
1154 | g_assert_not_reached (); |
1155 | break; |
1156 | } |
1157 | |
1158 | return TRUE; |
1159 | } |
1160 | |
1161 | void |
1162 | gtk_json_parser_rewind (GtkJsonParser *self) |
1163 | { |
1164 | if (self->error) |
1165 | return; |
1166 | |
1167 | switch (self->block->type) |
1168 | { |
1169 | case GTK_JSON_BLOCK_OBJECT: |
1170 | gtk_json_parser_pop_block (self); |
1171 | self->reader = self->block->value; |
1172 | gtk_json_parser_start_object (self); |
1173 | break; |
1174 | |
1175 | case GTK_JSON_BLOCK_ARRAY: |
1176 | gtk_json_parser_pop_block (self); |
1177 | self->reader = self->block->value; |
1178 | gtk_json_parser_start_array (self); |
1179 | break; |
1180 | |
1181 | case GTK_JSON_BLOCK_TOPLEVEL: |
1182 | self->reader = self->start; |
1183 | gtk_json_parser_skip_whitespace (self); |
1184 | if (gtk_json_parser_is_eof (self)) |
1185 | { |
1186 | gtk_json_parser_syntax_error_at (self, error_start: self->start, error_end: self->reader, format: "Empty document" ); |
1187 | } |
1188 | else |
1189 | { |
1190 | self->block->value = self->reader; |
1191 | gtk_json_parser_parse_value (self); |
1192 | } |
1193 | break; |
1194 | |
1195 | default: |
1196 | g_assert_not_reached (); |
1197 | return; |
1198 | } |
1199 | } |
1200 | |
1201 | gsize |
1202 | gtk_json_parser_get_depth (GtkJsonParser *self) |
1203 | { |
1204 | return self->block - self->blocks; |
1205 | } |
1206 | |
1207 | GtkJsonNode |
1208 | gtk_json_parser_get_node (GtkJsonParser *self) |
1209 | { |
1210 | if (self->error) |
1211 | return GTK_JSON_NONE; |
1212 | |
1213 | if (self->block->value == NULL) |
1214 | return GTK_JSON_NONE; |
1215 | |
1216 | return (json_character_table[*self->block->value] & JSON_CHARACTER_NODE_MASK); |
1217 | } |
1218 | |
1219 | const GError * |
1220 | gtk_json_parser_get_error (GtkJsonParser *self) |
1221 | { |
1222 | return self->error; |
1223 | } |
1224 | |
1225 | void |
1226 | gtk_json_parser_get_error_offset (GtkJsonParser *self, |
1227 | gsize *start, |
1228 | gsize *end) |
1229 | { |
1230 | const guchar *data; |
1231 | |
1232 | if (self->error == NULL) |
1233 | { |
1234 | if (start) |
1235 | *start = 0; |
1236 | if (end) |
1237 | *end = 0; |
1238 | return; |
1239 | } |
1240 | |
1241 | data = g_bytes_get_data (bytes: self->bytes, NULL); |
1242 | if (start) |
1243 | *start = self->error_start - data; |
1244 | if (end) |
1245 | *end = self->error_end - data; |
1246 | } |
1247 | |
1248 | void |
1249 | gtk_json_parser_get_error_location (GtkJsonParser *self, |
1250 | gsize *start_line, |
1251 | gsize *start_line_bytes, |
1252 | gsize *end_line, |
1253 | gsize *end_line_bytes) |
1254 | { |
1255 | const guchar *s, *line_start; |
1256 | gsize lines; |
1257 | |
1258 | if (self->error == NULL) |
1259 | { |
1260 | if (start_line) |
1261 | *start_line = 0; |
1262 | if (start_line_bytes) |
1263 | *start_line_bytes = 0; |
1264 | if (end_line) |
1265 | *end_line = 0; |
1266 | if (end_line_bytes) |
1267 | *end_line_bytes = 0; |
1268 | return; |
1269 | } |
1270 | |
1271 | line_start = self->start; |
1272 | lines = 0; |
1273 | |
1274 | for (s = json_skip_characters_until (start: line_start, end: self->error_start, type: NEWLINE); |
1275 | s < self->error_start; |
1276 | s = json_skip_characters_until (start: line_start, end: self->error_start, type: NEWLINE)) |
1277 | { |
1278 | if (s[0] == '\r' && s + 1 < self->error_start && s[1] == '\n') |
1279 | s++; |
1280 | lines++; |
1281 | line_start = s + 1; |
1282 | } |
1283 | |
1284 | if (start_line) |
1285 | *start_line = lines; |
1286 | if (start_line_bytes) |
1287 | *start_line_bytes = s - line_start; |
1288 | |
1289 | if (end_line == NULL && end_line_bytes == NULL) |
1290 | return; |
1291 | |
1292 | for (s = json_skip_characters_until (start: s, end: self->error_end, type: NEWLINE); |
1293 | s < self->error_end; |
1294 | s = json_skip_characters_until (start: line_start, end: self->error_end, type: NEWLINE)) |
1295 | { |
1296 | if (s[0] == '\r' && s + 1 < self->error_start && s[1] == '\n') |
1297 | s++; |
1298 | lines++; |
1299 | line_start = s + 1; |
1300 | } |
1301 | |
1302 | if (end_line) |
1303 | *end_line = lines; |
1304 | if (end_line_bytes) |
1305 | *end_line_bytes = s - line_start; |
1306 | } |
1307 | |
1308 | static gboolean |
1309 | gtk_json_parser_supports_member (GtkJsonParser *self) |
1310 | { |
1311 | if (self->error) |
1312 | return FALSE; |
1313 | |
1314 | if (self->block->type != GTK_JSON_BLOCK_OBJECT) |
1315 | return FALSE; |
1316 | |
1317 | if (self->block->member_name == NULL) |
1318 | return FALSE; |
1319 | |
1320 | return TRUE; |
1321 | } |
1322 | |
1323 | char * |
1324 | gtk_json_parser_get_member_name (GtkJsonParser *self) |
1325 | { |
1326 | if (!gtk_json_parser_supports_member (self)) |
1327 | return NULL; |
1328 | |
1329 | return gtk_json_unescape_string (escaped: self->block->member_name); |
1330 | } |
1331 | |
1332 | gboolean |
1333 | gtk_json_parser_has_member (GtkJsonParser *self, |
1334 | const char *name) |
1335 | { |
1336 | JsonStringIter iter; |
1337 | gsize found, len; |
1338 | |
1339 | if (!gtk_json_parser_supports_member (self)) |
1340 | return FALSE; |
1341 | |
1342 | found = 0; |
1343 | |
1344 | for (len = json_string_iter_init (iter: &iter, string: self->block->member_name); |
1345 | len > 0; |
1346 | len = json_string_iter_next (iter: &iter)) |
1347 | { |
1348 | const char *s = json_string_iter_get (iter: &iter); |
1349 | |
1350 | if (strncmp (s1: name + found, s2: s, n: len) != 0) |
1351 | return FALSE; |
1352 | |
1353 | found += len; |
1354 | } |
1355 | |
1356 | return TRUE; |
1357 | } |
1358 | |
1359 | gboolean |
1360 | gtk_json_parser_find_member (GtkJsonParser *self, |
1361 | const char *name) |
1362 | { |
1363 | if (!gtk_json_parser_supports_member (self)) |
1364 | { |
1365 | while (gtk_json_parser_next (self)); |
1366 | return FALSE; |
1367 | } |
1368 | |
1369 | gtk_json_parser_rewind (self); |
1370 | |
1371 | do |
1372 | { |
1373 | if (gtk_json_parser_has_member (self, name)) |
1374 | return TRUE; |
1375 | } |
1376 | while (gtk_json_parser_next (self)); |
1377 | |
1378 | return FALSE; |
1379 | } |
1380 | |
1381 | static gssize |
1382 | json_string_iter_run_select (const guchar *string_data, |
1383 | const char * const *options) |
1384 | { |
1385 | JsonStringIter iter; |
1386 | gssize i, j; |
1387 | gsize found, len; |
1388 | |
1389 | if (options == NULL || options[0] == NULL) |
1390 | return -1; |
1391 | |
1392 | found = 0; |
1393 | i = 0; |
1394 | |
1395 | for (len = json_string_iter_init (iter: &iter, string: string_data); |
1396 | len > 0; |
1397 | len = json_string_iter_next (iter: &iter)) |
1398 | { |
1399 | const char *s = json_string_iter_get (iter: &iter); |
1400 | |
1401 | if (strncmp (s1: options[i] + found, s2: s, n: len) != 0) |
1402 | { |
1403 | for (j = i + 1; options[j]; j++) |
1404 | { |
1405 | if (strncmp (s1: options[j], s2: options[i], n: found) == 0 && |
1406 | strncmp (s1: options[j] + found, s2: s, n: len) == 0) |
1407 | { |
1408 | i = j; |
1409 | break; |
1410 | } |
1411 | } |
1412 | if (j != i) |
1413 | return -1; |
1414 | } |
1415 | found += len; |
1416 | } |
1417 | |
1418 | if (options[i][found] == 0) |
1419 | return i; |
1420 | |
1421 | for (j = i + 1; options[j]; i++) |
1422 | { |
1423 | if (strncmp (s1: options[j], s2: options[i], n: found) != 0) |
1424 | continue; |
1425 | if (options[j][found] == 0) |
1426 | return j; |
1427 | } |
1428 | |
1429 | return -1; |
1430 | } |
1431 | |
1432 | gssize |
1433 | gtk_json_parser_select_member (GtkJsonParser *self, |
1434 | const char * const *options) |
1435 | { |
1436 | if (!gtk_json_parser_supports_member (self)) |
1437 | return -1; |
1438 | |
1439 | return json_string_iter_run_select (string_data: self->block->member_name, options); |
1440 | } |
1441 | |
1442 | gboolean |
1443 | gtk_json_parser_get_boolean (GtkJsonParser *self) |
1444 | { |
1445 | if (self->error) |
1446 | return FALSE; |
1447 | |
1448 | if (self->block->value == NULL) |
1449 | return FALSE; |
1450 | |
1451 | if (*self->block->value == 't') |
1452 | return TRUE; |
1453 | else if (*self->block->value == 'f') |
1454 | return FALSE; |
1455 | |
1456 | gtk_json_parser_type_error (self, format: "Expected a boolean value" ); |
1457 | return FALSE; |
1458 | } |
1459 | |
1460 | double |
1461 | gtk_json_parser_get_number (GtkJsonParser *self) |
1462 | { |
1463 | double result; |
1464 | |
1465 | if (self->error) |
1466 | return 0; |
1467 | |
1468 | if (self->block->value == NULL) |
1469 | return 0; |
1470 | |
1471 | if (!strchr (s: "-0123456789" , c: *self->block->value)) |
1472 | { |
1473 | gtk_json_parser_type_error (self, format: "Expected a number" ); |
1474 | return 0; |
1475 | } |
1476 | |
1477 | errno = 0; |
1478 | result = g_ascii_strtod (nptr: (const char *) self->block->value, NULL); |
1479 | |
1480 | if (errno) |
1481 | { |
1482 | if (errno == ERANGE) |
1483 | gtk_json_parser_value_error (self, format: "Number out of range" ); |
1484 | else |
1485 | gtk_json_parser_value_error (self, format: "%s" , g_strerror (errno)); |
1486 | |
1487 | return 0; |
1488 | } |
1489 | |
1490 | return result; |
1491 | } |
1492 | |
1493 | int |
1494 | gtk_json_parser_get_int (GtkJsonParser *self) |
1495 | { |
1496 | long result; |
1497 | char *end; |
1498 | |
1499 | if (self->error) |
1500 | return 0; |
1501 | |
1502 | if (self->block->value == NULL) |
1503 | return 0; |
1504 | |
1505 | if (!strchr (s: "-0123456789" , c: *self->block->value)) |
1506 | { |
1507 | gtk_json_parser_type_error (self, format: "Expected an intereger" ); |
1508 | return 0; |
1509 | } |
1510 | |
1511 | errno = 0; |
1512 | result = strtol (nptr: (const char *) self->block->value, endptr: &end, base: 10); |
1513 | if (*end == '.' || *end == 'e' || *end == 'E') |
1514 | { |
1515 | gtk_json_parser_type_error (self, format: "Expected an intereger" ); |
1516 | return 0; |
1517 | } |
1518 | |
1519 | if (errno) |
1520 | { |
1521 | if (errno == ERANGE) |
1522 | gtk_json_parser_value_error (self, format: "Number out of integer range" ); |
1523 | else |
1524 | gtk_json_parser_value_error (self, format: "%s" , g_strerror (errno)); |
1525 | |
1526 | return 0; |
1527 | } |
1528 | else if (result > G_MAXINT || result < G_MININT) |
1529 | { |
1530 | gtk_json_parser_value_error (self, format: "Number out of integer range" ); |
1531 | return 0; |
1532 | } |
1533 | |
1534 | return result; |
1535 | } |
1536 | |
1537 | guint |
1538 | gtk_json_parser_get_uint (GtkJsonParser *self) |
1539 | { |
1540 | gulong result; |
1541 | char *end; |
1542 | |
1543 | if (self->error) |
1544 | return 0; |
1545 | |
1546 | if (self->block->value == NULL) |
1547 | return 0; |
1548 | |
1549 | if (!strchr (s: "0123456789" , c: *self->block->value)) |
1550 | { |
1551 | gtk_json_parser_type_error (self, format: "Expected an unsigned intereger" ); |
1552 | return 0; |
1553 | } |
1554 | |
1555 | errno = 0; |
1556 | result = strtoul (nptr: (const char *) self->block->value, endptr: &end, base: 10); |
1557 | if (*end == '.' || *end == 'e' || *end == 'E') |
1558 | { |
1559 | gtk_json_parser_type_error (self, format: "Expected an unsigned intereger" ); |
1560 | return 0; |
1561 | } |
1562 | |
1563 | if (errno) |
1564 | { |
1565 | if (errno == ERANGE) |
1566 | gtk_json_parser_value_error (self, format: "Number out of unsignedinteger range" ); |
1567 | else |
1568 | gtk_json_parser_value_error (self, format: "%s" , g_strerror (errno)); |
1569 | |
1570 | return 0; |
1571 | } |
1572 | else if (result > G_MAXUINT) |
1573 | { |
1574 | gtk_json_parser_value_error (self, format: "Number out of unsigned integer range" ); |
1575 | return 0; |
1576 | } |
1577 | |
1578 | return result; |
1579 | } |
1580 | |
1581 | char * |
1582 | gtk_json_parser_get_string (GtkJsonParser *self) |
1583 | { |
1584 | if (self->error) |
1585 | return g_strdup (str: "" ); |
1586 | |
1587 | if (self->block->value == NULL) |
1588 | return g_strdup (str: "" ); |
1589 | |
1590 | if (*self->block->value != '"') |
1591 | { |
1592 | gtk_json_parser_type_error (self, format: "Expected a string" ); |
1593 | return g_strdup (str: "" ); |
1594 | } |
1595 | |
1596 | return gtk_json_unescape_string (escaped: self->block->value); |
1597 | } |
1598 | |
1599 | gssize |
1600 | gtk_json_parser_select_string (GtkJsonParser *self, |
1601 | const char * const *options) |
1602 | { |
1603 | if (self->error) |
1604 | return -1; |
1605 | |
1606 | if (self->block->value == NULL) |
1607 | return -1; |
1608 | |
1609 | if (*self->block->value != '"') |
1610 | { |
1611 | gtk_json_parser_type_error (self, format: "Expected a string" ); |
1612 | return -1; |
1613 | } |
1614 | |
1615 | return json_string_iter_run_select (string_data: self->block->value, options); |
1616 | } |
1617 | |
1618 | gboolean |
1619 | gtk_json_parser_start_object (GtkJsonParser *self) |
1620 | { |
1621 | if (self->error) |
1622 | return FALSE; |
1623 | |
1624 | if (!gtk_json_parser_try_char (self, c: '{')) |
1625 | { |
1626 | gtk_json_parser_type_error (self, format: "Expected an object" ); |
1627 | return FALSE; |
1628 | } |
1629 | |
1630 | gtk_json_parser_push_block (self, type: GTK_JSON_BLOCK_OBJECT); |
1631 | |
1632 | gtk_json_parser_skip_whitespace (self); |
1633 | if (gtk_json_parser_is_eof (self)) |
1634 | { |
1635 | gtk_json_parser_syntax_error_at (self, |
1636 | error_start: self->block[-1].value, |
1637 | error_end: self->reader, |
1638 | format: "Unterminated object" ); |
1639 | return FALSE; |
1640 | } |
1641 | if (gtk_json_parser_has_char (self, c: '}')) |
1642 | return TRUE; |
1643 | |
1644 | if (!gtk_json_parser_has_char (self, c: '"')) |
1645 | { |
1646 | gtk_json_parser_syntax_error (self, format: "Expected a string for object member name" ); |
1647 | return FALSE; |
1648 | } |
1649 | self->block->member_name = self->reader; |
1650 | |
1651 | if (!gtk_json_parser_parse_string (self)) |
1652 | return FALSE; |
1653 | gtk_json_parser_skip_whitespace (self); |
1654 | if (!gtk_json_parser_try_char (self, c: ':')) |
1655 | { |
1656 | gtk_json_parser_syntax_error (self, format: "Missing ':' after member name" ); |
1657 | return FALSE; |
1658 | } |
1659 | |
1660 | gtk_json_parser_skip_whitespace (self); |
1661 | self->block->value = self->reader; |
1662 | if (!gtk_json_parser_parse_value (self)) |
1663 | return FALSE; |
1664 | |
1665 | return TRUE; |
1666 | } |
1667 | |
1668 | gboolean |
1669 | gtk_json_parser_start_array (GtkJsonParser *self) |
1670 | { |
1671 | if (self->error) |
1672 | return FALSE; |
1673 | |
1674 | if (!gtk_json_parser_try_char (self, c: '[')) |
1675 | { |
1676 | gtk_json_parser_type_error (self, format: "Expected an array" ); |
1677 | return FALSE; |
1678 | } |
1679 | |
1680 | gtk_json_parser_push_block (self, type: GTK_JSON_BLOCK_ARRAY); |
1681 | gtk_json_parser_skip_whitespace (self); |
1682 | if (gtk_json_parser_is_eof (self)) |
1683 | { |
1684 | gtk_json_parser_syntax_error_at (self, |
1685 | error_start: self->block[-1].value, |
1686 | error_end: self->reader, |
1687 | format: "Unterminated array" ); |
1688 | return FALSE; |
1689 | } |
1690 | if (gtk_json_parser_has_char (self, c: ']')) |
1691 | { |
1692 | self->block->value = NULL; |
1693 | return TRUE; |
1694 | } |
1695 | self->block->value = self->reader; |
1696 | if (!gtk_json_parser_parse_value (self)) |
1697 | return FALSE; |
1698 | |
1699 | return TRUE; |
1700 | } |
1701 | |
1702 | gboolean |
1703 | gtk_json_parser_end (GtkJsonParser *self) |
1704 | { |
1705 | char bracket; |
1706 | |
1707 | g_return_val_if_fail (self != NULL, FALSE); |
1708 | |
1709 | while (gtk_json_parser_next (self)); |
1710 | |
1711 | if (self->error) |
1712 | return FALSE; |
1713 | |
1714 | switch (self->block->type) |
1715 | { |
1716 | case GTK_JSON_BLOCK_OBJECT: |
1717 | bracket = '}'; |
1718 | break; |
1719 | case GTK_JSON_BLOCK_ARRAY: |
1720 | bracket = ']'; |
1721 | break; |
1722 | case GTK_JSON_BLOCK_TOPLEVEL: |
1723 | default: |
1724 | g_return_val_if_reached (FALSE); |
1725 | } |
1726 | |
1727 | if (!gtk_json_parser_try_char (self, c: bracket)) |
1728 | { |
1729 | gtk_json_parser_syntax_error (self, format: "No terminating '%c'" , bracket); |
1730 | return FALSE; |
1731 | } |
1732 | |
1733 | gtk_json_parser_pop_block (self); |
1734 | |
1735 | return TRUE; |
1736 | } |
1737 | |
1738 | |