Line data Source code
1 : /* File: json_token_reader.c; Copyright and License: see below */
2 :
3 : #include "json/json_token_reader.h"
4 : #include "u8stream/universal_escaping_output_stream.h"
5 : #include "u8stream/universal_memory_output_stream.h"
6 : #include "u8/u8_trace.h"
7 : #include <string.h>
8 : #include <assert.h>
9 :
10 : static const char *const JSON_TOKENIZER_PRIVATE_DECODE_JSON_STRINGS[][2] = {
11 : { "\\t", "\x09" }, /* tab */
12 : { "\\n", "\x0a" }, /* newline */
13 : { "\\r", "\x0d" }, /* return */
14 : { "\\b", "\x08" }, /* backspace */
15 : { "\\f", "\x0c" }, /* form feed */
16 : { "\\\"", "\"" }, /* double quote */
17 : { "\\\\", "\\" }, /* backslash*/
18 : { "\\/", "/" }, /* forward slash could optionally be escaped */
19 : { NULL, NULL } /* for JSON, see rfc7159 */
20 : };
21 :
22 25 : void json_token_reader_init ( json_token_reader_t *this_, universal_input_stream_t *in_stream )
23 : {
24 25 : U8_TRACE_BEGIN();
25 25 : assert( NULL != in_stream );
26 :
27 25 : universal_buffer_input_stream_init( &((*this_).in_stream),
28 25 : &((*this_).input_buffer),
29 : sizeof((*this_).input_buffer),
30 : in_stream
31 : );
32 25 : (*this_).input_line = 1; /* the first line is 1, not 0 */
33 :
34 25 : U8_TRACE_END();
35 25 : }
36 :
37 49 : void json_token_reader_reinit ( json_token_reader_t *this_, universal_input_stream_t *in_stream )
38 : {
39 49 : U8_TRACE_BEGIN();
40 49 : assert( NULL != in_stream );
41 :
42 49 : universal_buffer_input_stream_destroy( &((*this_).in_stream) );
43 49 : universal_buffer_input_stream_init( &((*this_).in_stream),
44 49 : &((*this_).input_buffer),
45 : sizeof((*this_).input_buffer),
46 : in_stream
47 : );
48 49 : (*this_).input_line = 1; /* the first line is 1, not 0 */
49 :
50 49 : U8_TRACE_END();
51 49 : }
52 :
53 25 : void json_token_reader_destroy ( json_token_reader_t *this_ )
54 : {
55 25 : U8_TRACE_BEGIN();
56 :
57 25 : universal_buffer_input_stream_destroy( &((*this_).in_stream) );
58 :
59 25 : U8_TRACE_END();
60 25 : }
61 :
62 140 : u8_error_t json_token_reader_expect_begin_object ( json_token_reader_t *this_ )
63 : {
64 140 : U8_TRACE_BEGIN();
65 140 : u8_error_t result_err = U8_ERROR_NONE;
66 :
67 : /* skip whitespace */
68 140 : json_token_reader_private_skip_whitespace( this_ );
69 :
70 140 : if ( JSON_CONSTANTS_CHAR_BEGIN_OBJECT == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) )
71 : {
72 : /* expected token found */
73 138 : universal_buffer_input_stream_read_next( &((*this_).in_stream) );
74 : }
75 : else
76 : {
77 : /* expected token missing */
78 2 : result_err = U8_ERROR_PARSER_STRUCTURE;
79 : }
80 :
81 140 : U8_TRACE_END_ERR( result_err );
82 140 : return result_err;
83 : }
84 :
85 752 : u8_error_t json_token_reader_read_member_name ( json_token_reader_t *this_, utf8stringbuf_t out_name )
86 : {
87 752 : U8_TRACE_BEGIN();
88 752 : u8_error_t result_err = U8_ERROR_NONE;
89 :
90 752 : result_err = json_token_reader_read_string_value( this_, out_name );
91 :
92 752 : U8_TRACE_INFO_STR( "member name:", utf8stringbuf_get_string( out_name ) );
93 :
94 752 : U8_TRACE_END_ERR( result_err );
95 752 : return result_err;
96 : }
97 :
98 774 : u8_error_t json_token_reader_check_end_object ( json_token_reader_t *this_, bool *end_object )
99 : {
100 774 : U8_TRACE_BEGIN();
101 774 : assert( NULL != end_object );
102 774 : u8_error_t result_err = U8_ERROR_NONE;
103 :
104 : /* skip whitespace */
105 774 : json_token_reader_private_skip_whitespace( this_ );
106 :
107 774 : if ( JSON_CONSTANTS_CHAR_END_OBJECT == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) )
108 : {
109 : /* object-end token found */
110 125 : universal_buffer_input_stream_read_next( &((*this_).in_stream) );
111 125 : (*end_object) = true;
112 125 : U8_TRACE_INFO( "end object: true" );
113 : }
114 : else
115 : {
116 : /* expected token missing */
117 649 : (*end_object) = false;
118 : }
119 :
120 774 : U8_TRACE_END_ERR( result_err );
121 774 : return result_err;
122 : }
123 :
124 751 : u8_error_t json_token_reader_expect_name_separator ( json_token_reader_t *this_ )
125 : {
126 751 : U8_TRACE_BEGIN();
127 751 : u8_error_t result_err = U8_ERROR_NONE;
128 :
129 : /* skip whitespace */
130 751 : json_token_reader_private_skip_whitespace( this_ );
131 :
132 751 : if ( JSON_CONSTANTS_CHAR_NAME_SEPARATOR == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) )
133 : {
134 : /* expected token found */
135 751 : universal_buffer_input_stream_read_next( &((*this_).in_stream) );
136 : }
137 : else
138 : {
139 : /* expected token missing */
140 0 : result_err = U8_ERROR_PARSER_STRUCTURE;
141 : }
142 :
143 751 : U8_TRACE_END_ERR( result_err );
144 751 : return result_err;
145 : }
146 :
147 124 : u8_error_t json_token_reader_expect_begin_array ( json_token_reader_t *this_ )
148 : {
149 124 : U8_TRACE_BEGIN();
150 124 : u8_error_t result_err = U8_ERROR_NONE;
151 :
152 : /* skip whitespace */
153 124 : json_token_reader_private_skip_whitespace( this_ );
154 :
155 124 : if ( JSON_CONSTANTS_CHAR_BEGIN_ARRAY == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) )
156 : {
157 : /* expected token found */
158 124 : universal_buffer_input_stream_read_next( &((*this_).in_stream) );
159 : }
160 : else
161 : {
162 : /* expected token missing */
163 0 : result_err = U8_ERROR_PARSER_STRUCTURE;
164 : }
165 :
166 124 : U8_TRACE_END_ERR( result_err );
167 124 : return result_err;
168 : }
169 :
170 281 : u8_error_t json_token_reader_check_end_array ( json_token_reader_t *this_, bool *end_array )
171 : {
172 281 : U8_TRACE_BEGIN();
173 281 : assert( NULL != end_array );
174 281 : u8_error_t result_err = U8_ERROR_NONE;
175 :
176 : /* skip whitespace */
177 281 : json_token_reader_private_skip_whitespace( this_ );
178 :
179 281 : if ( JSON_CONSTANTS_CHAR_END_ARRAY == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ))
180 : {
181 : /* array-end token found */
182 118 : universal_buffer_input_stream_read_next( &((*this_).in_stream) );
183 118 : (*end_array) = true;
184 118 : U8_TRACE_INFO( "end array: true" );
185 : }
186 : else
187 : {
188 : /* expected token missing */
189 163 : (*end_array) = false;
190 : }
191 :
192 281 : U8_TRACE_END_ERR( result_err );
193 281 : return result_err;
194 : }
195 :
196 659 : u8_error_t json_token_reader_expect_value_separator ( json_token_reader_t *this_ )
197 : {
198 659 : U8_TRACE_BEGIN();
199 659 : u8_error_t result_err = U8_ERROR_NONE;
200 :
201 : /* skip whitespace */
202 659 : json_token_reader_private_skip_whitespace( this_ );
203 :
204 659 : if ( JSON_CONSTANTS_CHAR_VALUE_SEPARATOR == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) )
205 : {
206 : /* expected token found */
207 659 : universal_buffer_input_stream_read_next( &((*this_).in_stream) );
208 : }
209 : else
210 : {
211 : /* expected token missing */
212 0 : result_err = U8_ERROR_PARSER_STRUCTURE;
213 : }
214 :
215 659 : U8_TRACE_END_ERR( result_err );
216 659 : return result_err;
217 : }
218 :
219 9 : u8_error_t json_token_reader_get_value_type ( json_token_reader_t *this_, json_value_type_t *value_type )
220 : {
221 9 : U8_TRACE_BEGIN();
222 9 : assert( NULL != value_type );
223 9 : u8_error_t result_err = U8_ERROR_NONE;
224 :
225 : /* skip whitespace */
226 9 : json_token_reader_private_skip_whitespace( this_ );
227 :
228 : /* determine next token */
229 9 : char current = universal_buffer_input_stream_peek_next( &((*this_).in_stream) );
230 9 : if ( JSON_CONSTANTS_CHAR_BEGIN_OBJECT == current )
231 : {
232 1 : *value_type = JSON_VALUE_TYPE_OBJECT;
233 : }
234 8 : else if ( JSON_CONSTANTS_CHAR_BEGIN_ARRAY == current )
235 : {
236 1 : *value_type = JSON_VALUE_TYPE_ARRAY;
237 : }
238 7 : else if ( JSON_CONSTANTS_CHAR_BEGIN_STRING == current )
239 : {
240 1 : *value_type = JSON_VALUE_TYPE_STRING;
241 : }
242 6 : else if ( JSON_CONSTANTS_CHAR_BEGIN_FALSE == current )
243 : {
244 1 : *value_type = JSON_VALUE_TYPE_BOOLEAN;
245 : }
246 5 : else if ( JSON_CONSTANTS_CHAR_BEGIN_TRUE == current )
247 : {
248 1 : *value_type = JSON_VALUE_TYPE_BOOLEAN;
249 : }
250 4 : else if ( JSON_CONSTANTS_CHAR_BEGIN_NULL == current )
251 : {
252 1 : *value_type = JSON_VALUE_TYPE_NULL;
253 : }
254 3 : else if ( ( '-' == current ) || (( '0' <= current ) && ( current <= '9')) )
255 : {
256 : /* return number even if integer subtype */
257 1 : *value_type = JSON_VALUE_TYPE_NUMBER;
258 : }
259 : else
260 : {
261 2 : *value_type = JSON_VALUE_TYPE_UNDEF;
262 2 : result_err = U8_ERROR_PARSER_STRUCTURE; /* this could also be a lexical error (invalid next token) instead of unexpected next token */
263 : }
264 :
265 9 : U8_TRACE_END_ERR( result_err );
266 9 : return result_err;
267 : }
268 :
269 1101 : u8_error_t json_token_reader_read_string_value ( json_token_reader_t *this_, utf8stringbuf_t out_value )
270 : {
271 1101 : U8_TRACE_BEGIN();
272 1101 : u8_error_t result_err = U8_ERROR_NONE;
273 :
274 : /* skip whitespace */
275 1101 : json_token_reader_private_skip_whitespace( this_ );
276 :
277 : /* expect string begin */
278 1101 : if ( JSON_CONSTANTS_CHAR_BEGIN_STRING == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) )
279 : {
280 : /* expected token found */
281 1101 : universal_buffer_input_stream_read_next( &((*this_).in_stream) );
282 :
283 : universal_memory_output_stream_t mem_out;
284 1101 : universal_memory_output_stream_init( &mem_out,
285 1101 : utf8stringbuf_get_string(out_value),
286 : utf8stringbuf_get_size(out_value),
287 : UNIVERSAL_MEMORY_OUTPUT_STREAM_0TERM_UTF8
288 : );
289 :
290 : universal_escaping_output_stream_t esc_out;
291 1101 : universal_escaping_output_stream_init( &esc_out,
292 : &JSON_TOKENIZER_PRIVATE_DECODE_JSON_STRINGS,
293 : universal_memory_output_stream_get_output_stream( &mem_out )
294 : );
295 :
296 1101 : result_err = json_token_reader_private_read_string( this_,
297 : universal_escaping_output_stream_get_output_stream( &esc_out )
298 : );
299 :
300 1101 : const u8_error_t out_err = universal_escaping_output_stream_flush( &esc_out ); /* enforces 0-termination on mem_out */
301 1101 : universal_escaping_output_stream_destroy( &esc_out );
302 1101 : if ( 0 != out_err )
303 : {
304 35 : result_err = U8_ERROR_STRING_BUFFER_EXCEEDED;
305 : }
306 1101 : universal_memory_output_stream_destroy( &mem_out );
307 :
308 : /* expect string end */
309 1101 : const bool in_err
310 1101 : = ( JSON_CONSTANTS_CHAR_END_STRING != universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) );
311 1101 : if ( in_err )
312 : {
313 1 : result_err = U8_ERROR_LEXICAL_STRUCTURE;
314 : }
315 : else
316 : {
317 1100 : universal_buffer_input_stream_read_next( &((*this_).in_stream) );
318 :
319 1100 : if ( ! json_token_reader_private_is_value_end( this_ ) )
320 : {
321 1 : result_err = U8_ERROR_LEXICAL_STRUCTURE;
322 : }
323 : }
324 : }
325 : else
326 : {
327 : /* expected start token missing */
328 0 : result_err = U8_ERROR_PARSER_STRUCTURE;
329 : }
330 :
331 1101 : U8_TRACE_END_ERR( result_err );
332 1101 : return result_err;
333 : }
334 :
335 295 : u8_error_t json_token_reader_read_int_value ( json_token_reader_t *this_, int64_t *out_int )
336 : {
337 295 : U8_TRACE_BEGIN();
338 295 : assert( NULL != out_int );
339 295 : u8_error_t result_err = U8_ERROR_NONE;
340 :
341 : /* skip whitespace */
342 295 : json_token_reader_private_skip_whitespace( this_ );
343 :
344 295 : result_err = json_token_reader_private_parse_integer( this_, out_int );
345 :
346 295 : if ( ! json_token_reader_private_is_value_end( this_ ) )
347 : {
348 3 : result_err = U8_ERROR_LEXICAL_STRUCTURE;
349 : }
350 :
351 295 : U8_TRACE_END_ERR( result_err );
352 295 : return result_err;
353 : }
354 :
355 1 : u8_error_t json_token_reader_read_number_value ( json_token_reader_t *this_, double *out_number )
356 : {
357 1 : U8_TRACE_BEGIN();
358 1 : assert( NULL != out_number );
359 1 : u8_error_t result_err = U8_ERROR_NONE;
360 :
361 : /* skip whitespace */
362 1 : json_token_reader_private_skip_whitespace( this_ );
363 :
364 1 : result_err = json_token_reader_private_skip_number( this_ ); /* not yet implemented */
365 :
366 1 : if ( ! json_token_reader_private_is_value_end( this_ ) )
367 : {
368 0 : result_err = U8_ERROR_LEXICAL_STRUCTURE;
369 : }
370 : else
371 : {
372 1 : (*out_number) = 0.0;
373 1 : result_err = U8_ERROR_NOT_YET_IMPLEMENTED;
374 : }
375 :
376 1 : U8_TRACE_END_ERR( result_err );
377 1 : return result_err;
378 : }
379 :
380 2 : u8_error_t json_token_reader_read_boolean_value ( json_token_reader_t *this_, bool *out_bool )
381 : {
382 2 : U8_TRACE_BEGIN();
383 2 : assert( NULL != out_bool );
384 2 : u8_error_t result_err = U8_ERROR_NONE;
385 :
386 : /* skip whitespace */
387 2 : json_token_reader_private_skip_whitespace( this_ );
388 :
389 2 : char current = universal_buffer_input_stream_peek_next( &((*this_).in_stream) );
390 2 : if ( JSON_CONSTANTS_CHAR_BEGIN_FALSE == current )
391 : {
392 1 : (*out_bool) = false;
393 6 : for ( int f_pos = 0; f_pos < strlen(JSON_CONSTANTS_FALSE); f_pos ++ )
394 : {
395 5 : if ( JSON_CONSTANTS_FALSE[f_pos] == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) )
396 : {
397 5 : universal_buffer_input_stream_read_next( &((*this_).in_stream) );
398 : }
399 : else
400 : {
401 0 : result_err = U8_ERROR_LEXICAL_STRUCTURE;
402 : }
403 : }
404 1 : if ( ! json_token_reader_private_is_value_end( this_ ) )
405 : {
406 0 : result_err = U8_ERROR_LEXICAL_STRUCTURE;
407 : }
408 : }
409 1 : else if ( JSON_CONSTANTS_CHAR_BEGIN_TRUE == current )
410 : {
411 1 : (*out_bool) = true;
412 5 : for ( int t_pos = 0; t_pos < strlen(JSON_CONSTANTS_TRUE); t_pos ++ )
413 : {
414 4 : if ( JSON_CONSTANTS_TRUE[t_pos] == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) )
415 : {
416 4 : universal_buffer_input_stream_read_next( &((*this_).in_stream) );
417 : }
418 : else
419 : {
420 0 : result_err = U8_ERROR_LEXICAL_STRUCTURE;
421 : }
422 : }
423 1 : if ( ! json_token_reader_private_is_value_end( this_ ) )
424 : {
425 0 : result_err = U8_ERROR_LEXICAL_STRUCTURE;
426 : }
427 : }
428 : else
429 : {
430 0 : result_err = U8_ERROR_LEXICAL_STRUCTURE;
431 : }
432 :
433 2 : U8_TRACE_END_ERR( result_err );
434 2 : return result_err;
435 : }
436 :
437 1 : u8_error_t json_token_reader_expect_null_value ( json_token_reader_t *this_ )
438 : {
439 1 : U8_TRACE_BEGIN();
440 1 : u8_error_t result_err = U8_ERROR_NONE;
441 :
442 : /* skip whitespace */
443 1 : json_token_reader_private_skip_whitespace( this_ );
444 :
445 1 : char current = universal_buffer_input_stream_peek_next( &((*this_).in_stream) );
446 1 : if ( JSON_CONSTANTS_CHAR_BEGIN_NULL == current )
447 : {
448 5 : for ( int n_pos = 0; n_pos < strlen(JSON_CONSTANTS_NULL); n_pos ++ )
449 : {
450 4 : if ( JSON_CONSTANTS_NULL[n_pos] != universal_buffer_input_stream_read_next( &((*this_).in_stream) ) )
451 : {
452 0 : result_err = U8_ERROR_LEXICAL_STRUCTURE;
453 : }
454 : }
455 1 : if ( ! json_token_reader_private_is_value_end( this_ ) )
456 : {
457 0 : result_err = U8_ERROR_LEXICAL_STRUCTURE;
458 : }
459 : }
460 : else
461 : {
462 0 : result_err = U8_ERROR_PARSER_STRUCTURE;
463 : }
464 :
465 1 : U8_TRACE_END_ERR( result_err );
466 1 : return result_err;
467 : }
468 :
469 12 : u8_error_t json_token_reader_expect_eof ( json_token_reader_t *this_ )
470 : {
471 12 : U8_TRACE_BEGIN();
472 12 : u8_error_t result_err = U8_ERROR_NONE;
473 :
474 : /* skip whitespace */
475 12 : json_token_reader_private_skip_whitespace( this_ );
476 :
477 12 : char eof = universal_buffer_input_stream_peek_next( &((*this_).in_stream) );
478 12 : if ( '\0' == eof )
479 : {
480 : /* expected token found */
481 : }
482 : else
483 : {
484 : /* expected token missing */
485 0 : result_err = U8_ERROR_PARSER_STRUCTURE;
486 : }
487 :
488 12 : U8_TRACE_END_ERR( result_err );
489 12 : return result_err;
490 : }
491 :
492 :
493 : /*
494 : Copyright 2016-2024 Andreas Warnke
495 :
496 : Licensed under the Apache License, Version 2.0 (the "License");
497 : you may not use this file except in compliance with the License.
498 : You may obtain a copy of the License at
499 :
500 : http://www.apache.org/licenses/LICENSE-2.0
501 :
502 : Unless required by applicable law or agreed to in writing, software
503 : distributed under the License is distributed on an "AS IS" BASIS,
504 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
505 : See the License for the specific language governing permissions and
506 : limitations under the License.
507 : */
|