LCOV - code coverage report
Current view: top level - io/source/json - json_token_reader.c (source / functions) Hit Total Coverage
Test: crystal-facet-uml_v1.61.0_covts Lines: 194 208 93.3 %
Date: 2024-10-26 21:44:38 Functions: 17 17 100.0 %

          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             : */

Generated by: LCOV version 1.16