LCOV - code coverage report
Current view: top level - common - jsmn_parser.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 0 166 0.0 %
Date: 2018-01-11 Functions: 0 13 0.0 %

          Line data    Source code
       1             : /*
       2             : START OF LICENSE STUB
       3             :     DeDOS: Declarative Dispersion-Oriented Software
       4             :     Copyright (C) 2017 University of Pennsylvania, Georgetown University
       5             : 
       6             :     This program is free software: you can redistribute it and/or modify
       7             :     it under the terms of the GNU General Public License as published by
       8             :     the Free Software Foundation, either version 3 of the License, or
       9             :     (at your option) any later version.
      10             : 
      11             :     This program is distributed in the hope that it will be useful,
      12             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :     GNU General Public License for more details.
      15             : 
      16             :     You should have received a copy of the GNU General Public License
      17             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : END OF LICENSE STUB
      19             : */
      20             : /**
      21             :  * @file jsmn_parser.c
      22             :  *
      23             :  * General-purpose function to interact with JSMN library, and create
      24             :  * objects (potentially with circular references) from the parsed
      25             :  * json.
      26             :  */
      27             : 
      28             : #include "jsmn.h"
      29             : #include "jsmn_parser.h"
      30             : #include "logging.h"
      31             : #include <string.h>
      32             : #include <strings.h>
      33             : 
      34             : /** Destructively extracts an int from a jsmn token.
      35             :  * Sets the "end" char to \0, and converts converts the resulting
      36             :  * string to an integer
      37             :  *
      38             :  * @param tok - JSMN token to extract
      39             :  * @param j   - original json string
      40             :  * @returns   - integer
      41             :  */
      42           0 : int tok_to_int(jsmntok_t *tok, char *j){
      43           0 :     j[tok->end] = '\0';
      44           0 :     return atoi(&j[tok->start]);
      45             : }
      46             : 
      47             : /** Destructively extracts an int from a jsmn token.
      48             :  * Sets the "end" char to \0, and converts converts the resulting
      49             :  * string to a long integer
      50             :  *
      51             :  * @param tok - JSMN token to extract
      52             :  * @param j   - original json string
      53             :  * @returns   - long
      54             :  */
      55           0 : long tok_to_long(jsmntok_t *tok, char *j){
      56           0 :     j[tok->end] = '\0';
      57           0 :     return atol(&j[tok->start]);
      58             : }
      59             : 
      60             : 
      61             : /** Destructively extracts a c-string from a jsmn token.
      62             :  * Sets the "end" char to \0, and returns a pointer
      63             :  * to the start
      64             :  *
      65             :  * @param tok - JSMN token to extract
      66             :  * @param j   - original json string
      67             :  * @returns   - null-terminated char *
      68             :  */
      69           0 : char *tok_to_str(jsmntok_t *tok, char *j){
      70           0 :     j[tok->end] = '\0';
      71           0 :     return &j[tok->start];
      72             : }
      73             : 
      74             : /**
      75             :  * Global key mapping, giving which function should be called for each JSMN key
      76             :  */
      77             : static struct key_mapping *jsmn_key_map;
      78             : 
      79             : /**
      80             :  * Retries tokens which have been deferred
      81             :  */
      82             : static int retry_saved(struct json_state **saved, char *j);
      83             : 
      84             : /**
      85             :  * The object which is pased into the JSON parser to be filled
      86             :  */
      87             : static void * global_obj;
      88             : 
      89             : /**
      90             :  * Returns the initial object passed into the JSON parser
      91             :  */
      92           0 : void *get_root_jsmn_obj(){
      93           0 :     return global_obj;
      94             : }
      95             : 
      96           0 : int jsmn_ignore_list(jsmntok_t **tok, char *j, struct json_state *in, struct json_state **saved){
      97           0 :     int size = (*tok)->size;
      98             :     log(LOG_JSMN_PARSING, "Ignoring list of size %d", size);
      99           0 :     for (int i=0; i<size; i++){
     100           0 :         ++(*tok); // Move to the next value
     101           0 :         jsmn_ignore(tok, j, in, saved);
     102             :     }
     103           0 :     return 0;
     104             : }
     105             : 
     106           0 : int jsmn_ignore_obj(jsmntok_t **tok, char *j, struct json_state *in, struct json_state **saved){
     107           0 :     int size = (*tok)->size;
     108             :     log(LOG_JSMN_PARSING, "Ignoring object of size %d", size);
     109           0 :     for (int i=0; i<size; i++) {
     110           0 :         ++(*tok); // Ignore the key
     111           0 :         ++(*tok); // Move to the next value
     112           0 :         jsmn_ignore(tok, j, in, saved);
     113             :     }
     114           0 :     return 0;
     115             : }
     116             : 
     117             : /**
     118             :  * Ignores a JSMN value
     119             :  */
     120           0 : int jsmn_ignore(jsmntok_t **tok, char *j, struct json_state *in, struct json_state **saved){
     121           0 :     switch ( (*tok)->type ) {
     122             :         case JSMN_OBJECT:
     123           0 :             jsmn_ignore_obj(tok, j, in, saved);
     124           0 :             break;
     125             :         case JSMN_ARRAY:
     126           0 :             jsmn_ignore_list(tok, j, in, saved);
     127           0 :             break;
     128             :         default:
     129           0 :             break;
     130             :     }
     131           0 :     return 0;
     132             : }
     133             : 
     134             : 
     135           0 : int parse_file_into_obj(const char *filename, void *obj, struct key_mapping *km){
     136             :     // Set the global key map
     137           0 :     jsmn_key_map = km;
     138             : 
     139           0 :     FILE *file = fopen(filename, "r");
     140             : 
     141           0 :     if (file == NULL) {
     142           0 :         log_perror("Error opening %s", filename);
     143           0 :         return -1;
     144             :     }
     145             : 
     146             :     // Get the size of the file
     147           0 :     fseek(file, 0, SEEK_END);
     148           0 :     long fsize = ftell(file);
     149           0 :     rewind(file);
     150             : 
     151             :     // Read the file
     152           0 :     char *contents = malloc(fsize + 1);
     153           0 :     size_t rtn = fread(contents, fsize, 1, file);
     154           0 :     if (rtn == 0) {
     155           0 :         log_error("Could not read from file");
     156           0 :         return -1;
     157             :     }
     158           0 :     contents[fsize] = '\0';
     159           0 :     fclose(file);
     160             : 
     161           0 :     rtn = parse_str_into_obj(contents, obj, km);
     162           0 :     free(contents);
     163           0 :     return rtn;
     164             : }
     165             : 
     166             : /** The maximum number of times that a #PARSE_FN can return `1` before
     167             :  * an error is raised */
     168             : #define MAX_RETRIES 1024
     169             : 
     170             : 
     171           0 : int parse_str_into_obj(char *contents, void *obj, struct key_mapping *km) {
     172             : 
     173             :     // Initialize the JSON parser
     174             :     jsmn_parser parser;
     175           0 :     jsmn_init(&parser);
     176             :     // Get the number of necessary tokens
     177           0 :     int n_tokens = jsmn_parse(&parser, contents, strlen(contents), NULL, 16384);
     178             :     log(LOG_JSMN_PARSING, "Allocating %d tokens", n_tokens);
     179           0 :     jsmntok_t *tokens = malloc(n_tokens * sizeof(*tokens));
     180           0 :     jsmntok_t *tok_orig = tokens;
     181             :     // Parse the JSON
     182           0 :     jsmn_init(&parser);
     183           0 :     n_tokens = jsmn_parse(&parser, contents, strlen(contents), tokens, n_tokens);
     184             :     log(LOG_JSMN_PARSING, "Allocated %d tokens", n_tokens);
     185             : 
     186             :     // Set the top-level object so it can be retrieved elsewhere
     187           0 :     global_obj = obj;
     188             : 
     189             :     // Set the initial state for the first object
     190             :     // (type of 0 should indicate the root object)
     191           0 :     struct json_state init_state = {
     192             :         .parent_type = 0,
     193             :         .data = obj
     194             :     };
     195           0 :     struct json_state *saved_state = NULL;
     196             : 
     197             :     // Parse the jsmn tokens (assumes top-level item is an object)
     198           0 :     int rtn = parse_jsmn_obj(&tokens, contents, &init_state, &saved_state);
     199             : 
     200           0 :     if (rtn < 0){
     201           0 :         log_error("Error parsing JSMN");
     202           0 :         return -1;
     203             :     }
     204             : 
     205             :     log(LOG_JSMN_PARSING, "Parsed %d top-level objects", rtn);
     206             : 
     207           0 :     int n_retries = 0;
     208             :     // Go back through and retry each of the tokens that couldn't be parsed
     209             :     // the first time around
     210           0 :     while (saved_state != NULL){
     211             :         log(LOG_JSMN_PARSING, "Retrying saved states");
     212           0 :         rtn = retry_saved(&saved_state, contents);
     213           0 :         if (rtn < 0){
     214           0 :             log_error("Failed to re-interpret saved JSMN tokens");
     215           0 :             free(tok_orig);
     216           0 :             return -1;
     217             :         }
     218           0 :         n_retries++;
     219           0 :         if (n_retries > 100) {
     220           0 :             log_error("Something is wrong. Retried too many times");
     221           0 :             free(tok_orig);
     222           0 :             return -1;
     223             :         }
     224             :     }
     225           0 :     free(tok_orig);
     226           0 :     return 0;
     227             : }
     228             : 
     229             : /** Returns the function to parse a given key.
     230             :  *
     231             :  * @param key - the JSON key to parse
     232             :  * @param parent_type - the type of object in which this key is located
     233             :  * @return reference to function for parsing this key
     234             :  */
     235           0 : static jsmn_parsing_fn get_parse_fn(char *key, int parent_type){
     236             : 
     237           0 :     for (struct key_mapping *km = jsmn_key_map;
     238           0 :             km->parse != 0; km++){
     239           0 :         if (strncasecmp(key, km->key, strlen(km->key)) == 0 &&
     240           0 :                 km->parent_type == parent_type){
     241           0 :             return km->parse;
     242             :         }
     243             :     }
     244           0 :     return NULL;
     245             : }
     246             : 
     247             : /**
     248             :  * Retries the states that failed to parse the first time
     249             :  * due to dependencies.
     250             :  *
     251             :  * @param saved_states - the states which failed to parse the first time
     252             :  *                       (returned 1)
     253             :  * @param j - the entire JSON string
     254             :  * @return 0 if at least one saved state was parsed, -1 otherwise
     255             :  */
     256           0 : static int retry_saved(struct json_state **saved_states, char *j){
     257           0 :     struct json_state *prev = NULL;
     258           0 :     struct json_state *saved = *saved_states;
     259             : 
     260           0 :     int success = -1;
     261           0 :     char *key = NULL;
     262           0 :     int n_retries = 0;
     263           0 :     while (saved != NULL){
     264           0 :         jsmntok_t *tok = saved->tok;
     265           0 :         key = tok_to_str(tok, j);
     266             :         log(LOG_JSMN_PARSING, "Retrying key: %s", key);
     267             : 
     268           0 :         jsmn_parsing_fn parser = get_parse_fn(key, saved->parent_type);
     269           0 :         tok += 1;
     270           0 :         int rtn = parser(&tok, j, saved, saved_states);
     271             : 
     272           0 :         if (rtn < 0){
     273           0 :             log_error("Error retrying key %s", key);
     274           0 :             return -1;
     275           0 :         } else if (rtn == 0){
     276             :             log(LOG_JSMN_PARSING, "Successfully parsed retried key '%s'", key);
     277           0 :             success = 0;
     278           0 :             if (*saved_states == saved)
     279           0 :                 *saved_states = saved->next;
     280           0 :             if (prev != NULL) {
     281           0 :                 prev->next = saved->next;
     282             :             }
     283           0 :             struct json_state *tmp = saved;
     284           0 :             saved = saved->next;
     285           0 :             free(tmp);
     286           0 :         } else if (rtn == 1){
     287             :             log(LOG_JSMN_PARSING, "Will try again on the next pass...");
     288           0 :             prev = saved;
     289           0 :             saved = saved->next;
     290             :         } else {
     291           0 :             log_error("Unknown return code: %d", rtn);
     292           0 :             return -1;
     293             :         }
     294           0 :         if (n_retries++ > MAX_RETRIES) {
     295           0 :             log_error("Retried too many times. Something is wrong");
     296           0 :             return -1;
     297             :         }
     298             :     }
     299             : 
     300           0 :     if (success == -1 && key != NULL) {
     301           0 :         log_error("Failed while reprocessing key '%s' for missing dependencies", key);
     302           0 :         log_error("Value for improper key %s", key + (strlen(key) + 1));
     303             :     }
     304           0 :     return success;
     305             : }
     306             : 
     307             : /** Parses an array of JSMN objects.
     308             :  * Calls init() for each new object, then passes the returned json_state
     309             :  * to the next parsed object.
     310             :  *
     311             :  * @param tok - the current jsmn token to parse
     312             :  * @param j   - the entire json string
     313             :  * @param state - the current state of parsing
     314             :  * @param saved - list of states to be re-interpreted laster
     315             :  * @param init  - initialization function, returning a `struct json_state`
     316             :  * @return 0 on success, -1 on failure
     317             :  */
     318           0 : int parse_jsmn_obj_list(jsmntok_t **tok, char *j, struct json_state *state,
     319             :                                struct json_state **saved, jsmn_initializer init){
     320           0 :     ASSERT_JSMN_TYPE(*tok, JSMN_ARRAY, j);
     321           0 :     int size = (*tok)->size;
     322             : 
     323             :     // Advance to the object inside the list
     324           0 :     ++(*tok);
     325           0 :     for (int i=0; i<size; i++){
     326             :         log(LOG_JSMN_PARSING, "Parsing list item %d", i);
     327             :         // This is only for lists of OBJECTS.
     328           0 :         ASSERT_JSMN_TYPE(*tok, JSMN_OBJECT, j);
     329             : 
     330             :         // Construct the new state to be passed to the next object
     331           0 :         struct json_state new_state =  init(state, i);
     332           0 :         new_state.tok = *tok;
     333           0 :         new_state.next = NULL;
     334             : 
     335             :         // Parse the next object in the list
     336           0 :         int n_tokens = parse_jsmn_obj(tok, j, &new_state, saved);
     337             : 
     338             :         // Advance to the subsequent object
     339           0 :         ++(*tok);
     340           0 :         if (n_tokens < 0){
     341           0 :             return -1;
     342             :         }
     343             :     }
     344             :     // parse_jsmn_obj handles advancing to the next object, so we
     345             :     // want to rewind here so as not to advance twice
     346           0 :     --(*tok);
     347           0 :     return 0;
     348             : }
     349             : 
     350             : /** Parses a single JSMN object utilizing the provided (global) key map.
     351             :  *
     352             :  * @param tok - pointer to current token to be parsed (advances automatically)
     353             :  * @param j   - entire json string being parsed
     354             :  * @param state - curernt state of parsing, including the data structure being parsed into
     355             :  * @param saved - JSON entries on which parsing has been deferred for later
     356             :  *
     357             :  */
     358           0 : int parse_jsmn_obj(jsmntok_t **tok, char *j, struct json_state *state,
     359             :                           struct json_state **saved){
     360           0 :     ASSERT_JSMN_TYPE(*tok, JSMN_OBJECT, j);
     361             : 
     362           0 :     int size = (*tok)->size;
     363             : 
     364           0 :     ++(*tok);
     365             :     //tpok+=1;
     366           0 :     int parent_type = state->parent_type;
     367             : 
     368           0 :     for (int i=0; i<size; i++){
     369           0 :         ASSERT_JSMN_TYPE(*tok, JSMN_STRING, j);
     370             : 
     371           0 :         char *key = tok_to_str(*tok, j);
     372             : 
     373           0 :         jsmn_parsing_fn parse = get_parse_fn(key, parent_type);
     374           0 :         if (parse == NULL){
     375           0 :             log_error("No matching key %s for type %d",
     376             :                       tok_to_str(*tok, j), parent_type);
     377           0 :             return -1;
     378             :         }
     379             : 
     380           0 :         jsmntok_t *pre_tok = *tok;
     381           0 :         void *pre_data = state->data;
     382           0 :         state->tok = ++(*tok);
     383           0 :         int rtn = parse(tok, j, state, saved);
     384             : 
     385           0 :         if (rtn < 0){
     386           0 :             log_error("Error parsing token at %s", &j[pre_tok->start]);
     387           0 :             return -1;
     388           0 :         } else if (rtn > 0){
     389             :             log(LOG_JSMN_PARSING, "Deferring parsing of %s", key);
     390           0 :             struct json_state *to_save = malloc(sizeof(*to_save));
     391           0 :             to_save->data = pre_data;
     392           0 :             to_save->parent_type = parent_type;
     393           0 :             to_save->next = *saved;
     394           0 :             to_save->tok = pre_tok;
     395           0 :             *saved = to_save;
     396             :         } else {
     397             :             log(LOG_JSMN_PARSING, "Successfully parsed %s", key);
     398             :         }
     399           0 :         ++(*tok);
     400             :     }
     401           0 :     --(*tok);
     402           0 :     return size;
     403             : }

Generated by: LCOV version 1.10