LCOV - code coverage report
Current view: top level - io/source/json - json_token_reader.c (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.63.2_covts Lines: 93.3 % 208 194
Test Date: 2025-05-01 10:10:14 Functions: 100.0 % 17 17

            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           28 : void json_token_reader_init ( json_token_reader_t *this_, universal_input_stream_t *in_stream )
      23              : {
      24           28 :     U8_TRACE_BEGIN();
      25           28 :     assert( NULL != in_stream );
      26              : 
      27           28 :     universal_buffer_input_stream_init( &((*this_).in_stream),
      28           28 :                                         &((*this_).input_buffer),
      29              :                                         sizeof((*this_).input_buffer),
      30              :                                         in_stream
      31              :                                       );
      32           28 :     (*this_).input_line = 1;  /* the first line is 1, not 0 */
      33              : 
      34           28 :     U8_TRACE_END();
      35           28 : }
      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           28 : void json_token_reader_destroy ( json_token_reader_t *this_ )
      54              : {
      55           28 :     U8_TRACE_BEGIN();
      56              : 
      57           28 :     universal_buffer_input_stream_destroy( &((*this_).in_stream) );
      58              : 
      59           28 :     U8_TRACE_END();
      60           28 : }
      61              : 
      62          146 : u8_error_t json_token_reader_expect_begin_object ( json_token_reader_t *this_ )
      63              : {
      64          146 :     U8_TRACE_BEGIN();
      65          146 :     u8_error_t result_err = U8_ERROR_NONE;
      66              : 
      67              :     /* skip whitespace */
      68          146 :     json_token_reader_private_skip_whitespace( this_ );
      69              : 
      70          146 :     if ( JSON_CONSTANTS_CHAR_BEGIN_OBJECT == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) )
      71              :     {
      72              :         /* expected token found */
      73          144 :         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          146 :     U8_TRACE_END_ERR( result_err );
      82          146 :     return result_err;
      83              : }
      84              : 
      85          785 : u8_error_t json_token_reader_read_member_name ( json_token_reader_t *this_, utf8stringbuf_t out_name )
      86              : {
      87          785 :     U8_TRACE_BEGIN();
      88          785 :     u8_error_t result_err = U8_ERROR_NONE;
      89              : 
      90          785 :     result_err = json_token_reader_read_string_value( this_, out_name );
      91              : 
      92          785 :     U8_TRACE_INFO_STR( "member name:", utf8stringbuf_get_string( &out_name ) );
      93              : 
      94          785 :     U8_TRACE_END_ERR( result_err );
      95          785 :     return result_err;
      96              : }
      97              : 
      98          801 : u8_error_t json_token_reader_check_end_object ( json_token_reader_t *this_, bool *end_object )
      99              : {
     100          801 :     U8_TRACE_BEGIN();
     101          801 :     assert( NULL != end_object );
     102          801 :     u8_error_t result_err = U8_ERROR_NONE;
     103              : 
     104              :     /* skip whitespace */
     105          801 :     json_token_reader_private_skip_whitespace( this_ );
     106              : 
     107          801 :     if ( JSON_CONSTANTS_CHAR_END_OBJECT == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) )
     108              :     {
     109              :         /* object-end token found */
     110          131 :         universal_buffer_input_stream_read_next( &((*this_).in_stream) );
     111          131 :         (*end_object) = true;
     112          131 :         U8_TRACE_INFO( "end object: true" );
     113              :     }
     114              :     else
     115              :     {
     116              :         /* expected token missing */
     117          670 :         (*end_object) = false;
     118              :     }
     119              : 
     120          801 :     U8_TRACE_END_ERR( result_err );
     121          801 :     return result_err;
     122              : }
     123              : 
     124          784 : u8_error_t json_token_reader_expect_name_separator ( json_token_reader_t *this_ )
     125              : {
     126          784 :     U8_TRACE_BEGIN();
     127          784 :     u8_error_t result_err = U8_ERROR_NONE;
     128              : 
     129              :     /* skip whitespace */
     130          784 :     json_token_reader_private_skip_whitespace( this_ );
     131              : 
     132          784 :     if ( JSON_CONSTANTS_CHAR_NAME_SEPARATOR == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) )
     133              :     {
     134              :         /* expected token found */
     135          784 :         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          784 :     U8_TRACE_END_ERR( result_err );
     144          784 :     return result_err;
     145              : }
     146              : 
     147          133 : u8_error_t json_token_reader_expect_begin_array ( json_token_reader_t *this_ )
     148              : {
     149          133 :     U8_TRACE_BEGIN();
     150          133 :     u8_error_t result_err = U8_ERROR_NONE;
     151              : 
     152              :     /* skip whitespace */
     153          133 :     json_token_reader_private_skip_whitespace( this_ );
     154              : 
     155          133 :     if ( JSON_CONSTANTS_CHAR_BEGIN_ARRAY == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) )
     156              :     {
     157              :         /* expected token found */
     158          133 :         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          133 :     U8_TRACE_END_ERR( result_err );
     167          133 :     return result_err;
     168              : }
     169              : 
     170          290 : u8_error_t json_token_reader_check_end_array ( json_token_reader_t *this_, bool *end_array )
     171              : {
     172          290 :     U8_TRACE_BEGIN();
     173          290 :     assert( NULL != end_array );
     174          290 :     u8_error_t result_err = U8_ERROR_NONE;
     175              : 
     176              :     /* skip whitespace */
     177          290 :     json_token_reader_private_skip_whitespace( this_ );
     178              : 
     179          290 :     if ( JSON_CONSTANTS_CHAR_END_ARRAY == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ))
     180              :     {
     181              :         /* array-end token found */
     182          127 :         universal_buffer_input_stream_read_next( &((*this_).in_stream) );
     183          127 :         (*end_array) = true;
     184          127 :         U8_TRACE_INFO( "end array: true" );
     185              :     }
     186              :     else
     187              :     {
     188              :         /* expected token missing */
     189          163 :         (*end_array) = false;
     190              :     }
     191              : 
     192          290 :     U8_TRACE_END_ERR( result_err );
     193          290 :     return result_err;
     194              : }
     195              : 
     196          686 : u8_error_t json_token_reader_expect_value_separator ( json_token_reader_t *this_ )
     197              : {
     198          686 :     U8_TRACE_BEGIN();
     199          686 :     u8_error_t result_err = U8_ERROR_NONE;
     200              : 
     201              :     /* skip whitespace */
     202          686 :     json_token_reader_private_skip_whitespace( this_ );
     203              : 
     204          686 :     if ( JSON_CONSTANTS_CHAR_VALUE_SEPARATOR == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) )
     205              :     {
     206              :         /* expected token found */
     207          686 :         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          686 :     U8_TRACE_END_ERR( result_err );
     216          686 :     return result_err;
     217              : }
     218              : 
     219           30 : u8_error_t json_token_reader_get_value_type ( json_token_reader_t *this_, json_value_type_t *value_type )
     220              : {
     221           30 :     U8_TRACE_BEGIN();
     222           30 :     assert( NULL != value_type );
     223           30 :     u8_error_t result_err = U8_ERROR_NONE;
     224              : 
     225              :     /* skip whitespace */
     226           30 :     json_token_reader_private_skip_whitespace( this_ );
     227              : 
     228              :     /* determine next token */
     229           30 :     char current = universal_buffer_input_stream_peek_next( &((*this_).in_stream) );
     230           30 :     if ( JSON_CONSTANTS_CHAR_BEGIN_OBJECT == current )
     231              :     {
     232            1 :         *value_type = JSON_VALUE_TYPE_OBJECT;
     233              :     }
     234           29 :     else if ( JSON_CONSTANTS_CHAR_BEGIN_ARRAY == current )
     235              :     {
     236            1 :         *value_type = JSON_VALUE_TYPE_ARRAY;
     237              :     }
     238           28 :     else if ( JSON_CONSTANTS_CHAR_BEGIN_STRING == current )
     239              :     {
     240           16 :         *value_type = JSON_VALUE_TYPE_STRING;
     241              :     }
     242           12 :     else if ( JSON_CONSTANTS_CHAR_BEGIN_FALSE == current )
     243              :     {
     244            1 :         *value_type = JSON_VALUE_TYPE_BOOLEAN;
     245              :     }
     246           11 :     else if ( JSON_CONSTANTS_CHAR_BEGIN_TRUE == current )
     247              :     {
     248            1 :         *value_type = JSON_VALUE_TYPE_BOOLEAN;
     249              :     }
     250           10 :     else if ( JSON_CONSTANTS_CHAR_BEGIN_NULL == current )
     251              :     {
     252            1 :         *value_type = JSON_VALUE_TYPE_NULL;
     253              :     }
     254            9 :     else if ( ( '-' == current ) || (( '0' <= current ) && ( current <= '9')) )
     255              :     {
     256              :         /* return number even if integer subtype */
     257            7 :         *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           30 :     U8_TRACE_END_ERR( result_err );
     266           30 :     return result_err;
     267              : }
     268              : 
     269         1149 : u8_error_t json_token_reader_read_string_value ( json_token_reader_t *this_, utf8stringbuf_t out_value )
     270              : {
     271         1149 :     U8_TRACE_BEGIN();
     272         1149 :     u8_error_t result_err = U8_ERROR_NONE;
     273              : 
     274              :     /* skip whitespace */
     275         1149 :     json_token_reader_private_skip_whitespace( this_ );
     276              : 
     277              :     /* expect string begin */
     278         1149 :     if ( JSON_CONSTANTS_CHAR_BEGIN_STRING == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) )
     279              :     {
     280              :         /* expected token found */
     281         1149 :         universal_buffer_input_stream_read_next( &((*this_).in_stream) );
     282              : 
     283              :         universal_memory_output_stream_t mem_out;
     284         1149 :         universal_memory_output_stream_init( &mem_out,
     285         1149 :                                              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         1149 :         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         1149 :         result_err = json_token_reader_private_read_string( this_,
     297              :                                                             universal_escaping_output_stream_get_output_stream( &esc_out )
     298              :                                                           );
     299              : 
     300         1149 :         const u8_error_t out_err = universal_escaping_output_stream_flush( &esc_out );  /* enforces 0-termination on mem_out */
     301         1149 :         universal_escaping_output_stream_destroy( &esc_out );
     302         1149 :         if ( 0 != out_err )
     303              :         {
     304           50 :             result_err = U8_ERROR_STRING_BUFFER_EXCEEDED;
     305              :         }
     306         1149 :         universal_memory_output_stream_destroy( &mem_out );
     307              : 
     308              :         /* expect string end */
     309         1149 :         const bool in_err
     310         1149 :             = ( JSON_CONSTANTS_CHAR_END_STRING != universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) );
     311         1149 :         if ( in_err )
     312              :         {
     313            1 :             result_err = U8_ERROR_LEXICAL_STRUCTURE;
     314              :         }
     315              :         else
     316              :         {
     317         1148 :             universal_buffer_input_stream_read_next( &((*this_).in_stream) );
     318              : 
     319         1148 :             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         1149 :     U8_TRACE_END_ERR( result_err );
     332         1149 :     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            7 : u8_error_t json_token_reader_read_number_value ( json_token_reader_t *this_, double *out_number )
     356              : {
     357            7 :     U8_TRACE_BEGIN();
     358            7 :     assert( NULL != out_number );
     359            7 :     u8_error_t result_err = U8_ERROR_NONE;
     360              : 
     361              :     /* skip whitespace */
     362            7 :     json_token_reader_private_skip_whitespace( this_ );
     363              : 
     364            7 :     result_err = json_token_reader_private_skip_number( this_ );  /* not yet implemented */
     365              : 
     366            7 :     if ( ! json_token_reader_private_is_value_end( this_ ) )
     367              :     {
     368            0 :         result_err = U8_ERROR_LEXICAL_STRUCTURE;
     369              :     }
     370              :     else
     371              :     {
     372            7 :         (*out_number) = 0.0;
     373            7 :         result_err = U8_ERROR_NOT_YET_IMPLEMENTED;
     374              :     }
     375              : 
     376            7 :     U8_TRACE_END_ERR( result_err );
     377            7 :     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           15 : u8_error_t json_token_reader_expect_eof ( json_token_reader_t *this_ )
     470              : {
     471           15 :     U8_TRACE_BEGIN();
     472           15 :     u8_error_t result_err = U8_ERROR_NONE;
     473              : 
     474              :     /* skip whitespace */
     475           15 :     json_token_reader_private_skip_whitespace( this_ );
     476              : 
     477           15 :     char eof = universal_buffer_input_stream_peek_next( &((*this_).in_stream) );
     478           15 :     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           15 :     U8_TRACE_END_ERR( result_err );
     489           15 :     return result_err;
     490              : }
     491              : 
     492              : 
     493              : /*
     494              : Copyright 2016-2025 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              : */
        

Generated by: LCOV version 2.0-1