My Project
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros
jsmn_parser.c
Go to the documentation of this file.
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 */
28 #include "jsmn.h"
29 #include "jsmn_parser.h"
30 #include "logging.h"
31 #include <string.h>
32 #include <strings.h>
33 
42 int tok_to_int(jsmntok_t *tok, char *j){
43  j[tok->end] = '\0';
44  return atoi(&j[tok->start]);
45 }
46 
55 long tok_to_long(jsmntok_t *tok, char *j){
56  j[tok->end] = '\0';
57  return atol(&j[tok->start]);
58 }
59 
60 
69 char *tok_to_str(jsmntok_t *tok, char *j){
70  j[tok->end] = '\0';
71  return &j[tok->start];
72 }
73 
77 static struct key_mapping *jsmn_key_map;
78 
82 static int retry_saved(struct json_state **saved, char *j);
83 
87 static void * global_obj;
88 
93  return global_obj;
94 }
95 
96 int jsmn_ignore_list(jsmntok_t **tok, char *j, struct json_state *in, struct json_state **saved){
97  int size = (*tok)->size;
98  log(LOG_JSMN_PARSING, "Ignoring list of size %d", size);
99  for (int i=0; i<size; i++){
100  ++(*tok); // Move to the next value
101  jsmn_ignore(tok, j, in, saved);
102  }
103  return 0;
104 }
105 
106 int jsmn_ignore_obj(jsmntok_t **tok, char *j, struct json_state *in, struct json_state **saved){
107  int size = (*tok)->size;
108  log(LOG_JSMN_PARSING, "Ignoring object of size %d", size);
109  for (int i=0; i<size; i++) {
110  ++(*tok); // Ignore the key
111  ++(*tok); // Move to the next value
112  jsmn_ignore(tok, j, in, saved);
113  }
114  return 0;
115 }
116 
120 int jsmn_ignore(jsmntok_t **tok, char *j, struct json_state *in, struct json_state **saved){
121  switch ( (*tok)->type ) {
122  case JSMN_OBJECT:
123  jsmn_ignore_obj(tok, j, in, saved);
124  break;
125  case JSMN_ARRAY:
126  jsmn_ignore_list(tok, j, in, saved);
127  break;
128  default:
129  break;
130  }
131  return 0;
132 }
133 
134 
135 int parse_file_into_obj(const char *filename, void *obj, struct key_mapping *km){
136  // Set the global key map
137  jsmn_key_map = km;
138 
139  FILE *file = fopen(filename, "r");
140 
141  if (file == NULL) {
142  log_perror("Error opening %s", filename);
143  return -1;
144  }
145 
146  // Get the size of the file
147  fseek(file, 0, SEEK_END);
148  long fsize = ftell(file);
149  rewind(file);
150 
151  // Read the file
152  char *contents = malloc(fsize + 1);
153  size_t rtn = fread(contents, fsize, 1, file);
154  if (rtn == 0) {
155  log_error("Could not read from file");
156  return -1;
157  }
158  contents[fsize] = '\0';
159  fclose(file);
160 
161  rtn = parse_str_into_obj(contents, obj, km);
162  free(contents);
163  return rtn;
164 }
165 
168 #define MAX_RETRIES 1024
169 
170 
171 int parse_str_into_obj(char *contents, void *obj, struct key_mapping *km) {
172 
173  // Initialize the JSON parser
174  jsmn_parser parser;
175  jsmn_init(&parser);
176  // Get the number of necessary tokens
177  int n_tokens = jsmn_parse(&parser, contents, strlen(contents), NULL, 16384);
178  log(LOG_JSMN_PARSING, "Allocating %d tokens", n_tokens);
179  jsmntok_t *tokens = malloc(n_tokens * sizeof(*tokens));
180  jsmntok_t *tok_orig = tokens;
181  // Parse the JSON
182  jsmn_init(&parser);
183  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  global_obj = obj;
188 
189  // Set the initial state for the first object
190  // (type of 0 should indicate the root object)
191  struct json_state init_state = {
192  .parent_type = 0,
193  .data = obj
194  };
195  struct json_state *saved_state = NULL;
196 
197  // Parse the jsmn tokens (assumes top-level item is an object)
198  int rtn = parse_jsmn_obj(&tokens, contents, &init_state, &saved_state);
199 
200  if (rtn < 0){
201  log_error("Error parsing JSMN");
202  return -1;
203  }
204 
205  log(LOG_JSMN_PARSING, "Parsed %d top-level objects", rtn);
206 
207  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  while (saved_state != NULL){
211  log(LOG_JSMN_PARSING, "Retrying saved states");
212  rtn = retry_saved(&saved_state, contents);
213  if (rtn < 0){
214  log_error("Failed to re-interpret saved JSMN tokens");
215  free(tok_orig);
216  return -1;
217  }
218  n_retries++;
219  if (n_retries > 100) {
220  log_error("Something is wrong. Retried too many times");
221  free(tok_orig);
222  return -1;
223  }
224  }
225  free(tok_orig);
226  return 0;
227 }
228 
235 static jsmn_parsing_fn get_parse_fn(char *key, int parent_type){
236 
237  for (struct key_mapping *km = jsmn_key_map;
238  km->parse != 0; km++){
239  if (strncasecmp(key, km->key, strlen(km->key)) == 0 &&
240  km->parent_type == parent_type){
241  return km->parse;
242  }
243  }
244  return NULL;
245 }
246 
256 static int retry_saved(struct json_state **saved_states, char *j){
257  struct json_state *prev = NULL;
258  struct json_state *saved = *saved_states;
259 
260  int success = -1;
261  char *key = NULL;
262  int n_retries = 0;
263  while (saved != NULL){
264  jsmntok_t *tok = saved->tok;
265  key = tok_to_str(tok, j);
266  log(LOG_JSMN_PARSING, "Retrying key: %s", key);
267 
268  jsmn_parsing_fn parser = get_parse_fn(key, saved->parent_type);
269  tok += 1;
270  int rtn = parser(&tok, j, saved, saved_states);
271 
272  if (rtn < 0){
273  log_error("Error retrying key %s", key);
274  return -1;
275  } else if (rtn == 0){
276  log(LOG_JSMN_PARSING, "Successfully parsed retried key '%s'", key);
277  success = 0;
278  if (*saved_states == saved)
279  *saved_states = saved->next;
280  if (prev != NULL) {
281  prev->next = saved->next;
282  }
283  struct json_state *tmp = saved;
284  saved = saved->next;
285  free(tmp);
286  } else if (rtn == 1){
287  log(LOG_JSMN_PARSING, "Will try again on the next pass...");
288  prev = saved;
289  saved = saved->next;
290  } else {
291  log_error("Unknown return code: %d", rtn);
292  return -1;
293  }
294  if (n_retries++ > MAX_RETRIES) {
295  log_error("Retried too many times. Something is wrong");
296  return -1;
297  }
298  }
299 
300  if (success == -1 && key != NULL) {
301  log_error("Failed while reprocessing key '%s' for missing dependencies", key);
302  log_error("Value for improper key %s", key + (strlen(key) + 1));
303  }
304  return success;
305 }
306 
319  struct json_state **saved, jsmn_initializer init){
320  ASSERT_JSMN_TYPE(*tok, JSMN_ARRAY, j);
321  int size = (*tok)->size;
322 
323  // Advance to the object inside the list
324  ++(*tok);
325  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  ASSERT_JSMN_TYPE(*tok, JSMN_OBJECT, j);
329 
330  // Construct the new state to be passed to the next object
331  struct json_state new_state = init(state, i);
332  new_state.tok = *tok;
333  new_state.next = NULL;
334 
335  // Parse the next object in the list
336  int n_tokens = parse_jsmn_obj(tok, j, &new_state, saved);
337 
338  // Advance to the subsequent object
339  ++(*tok);
340  if (n_tokens < 0){
341  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  --(*tok);
347  return 0;
348 }
349 
358 int parse_jsmn_obj(jsmntok_t **tok, char *j, struct json_state *state,
359  struct json_state **saved){
360  ASSERT_JSMN_TYPE(*tok, JSMN_OBJECT, j);
361 
362  int size = (*tok)->size;
363 
364  ++(*tok);
365  //tpok+=1;
366  int parent_type = state->parent_type;
367 
368  for (int i=0; i<size; i++){
369  ASSERT_JSMN_TYPE(*tok, JSMN_STRING, j);
370 
371  char *key = tok_to_str(*tok, j);
372 
373  jsmn_parsing_fn parse = get_parse_fn(key, parent_type);
374  if (parse == NULL){
375  log_error("No matching key %s for type %d",
376  tok_to_str(*tok, j), parent_type);
377  return -1;
378  }
379 
380  jsmntok_t *pre_tok = *tok;
381  void *pre_data = state->data;
382  state->tok = ++(*tok);
383  int rtn = parse(tok, j, state, saved);
384 
385  if (rtn < 0){
386  log_error("Error parsing token at %s", &j[pre_tok->start]);
387  return -1;
388  } else if (rtn > 0){
389  log(LOG_JSMN_PARSING, "Deferring parsing of %s", key);
390  struct json_state *to_save = malloc(sizeof(*to_save));
391  to_save->data = pre_data;
392  to_save->parent_type = parent_type;
393  to_save->next = *saved;
394  to_save->tok = pre_tok;
395  *saved = to_save;
396  } else {
397  log(LOG_JSMN_PARSING, "Successfully parsed %s", key);
398  }
399  ++(*tok);
400  }
401  --(*tok);
402  return size;
403 }
jsmn_parsing_fn parse
The function to be called when this string is seen at the appropriate place in the input JSON...
Definition: jsmn_parser.h:182
JSON token description.
Definition: jsmn.h:61
char * tok_to_str(jsmntok_t *tok, char *j)
Destructively extracts a c-string from a jsmn token.
Definition: jsmn_parser.c:69
int jsmn_ignore(jsmntok_t **tok, char *j, struct json_state *in, struct json_state **saved)
Ignores a JSMN value.
Definition: jsmn_parser.c:120
static struct key_mapping * jsmn_key_map
Global key mapping, giving which function should be called for each JSMN key.
Definition: jsmn_parser.c:77
long tok_to_long(jsmntok_t *tok, char *j)
Destructively extracts an int from a jsmn token.
Definition: jsmn_parser.c:55
int jsmn_ignore_list(jsmntok_t **tok, char *j, struct json_state *in, struct json_state **saved)
Definition: jsmn_parser.c:96
#define log_perror(fmt,...)
Definition: logging.h:102
Logging of status messages to the terminal.
Structure to hold state while parsing JSON.
Definition: jsmn_parser.h:49
int parent_type
The type of object that is being create.
Definition: jsmn_parser.h:51
int(* jsmn_parsing_fn)(jsmntok_t **tok, char *j, struct json_state *state, struct json_state **saved)
Typedef for a jsmn parsing function.
Definition: jsmn_parser.h:66
Structure to map a key + state to a function.
Definition: jsmn_parser.h:178
int tok_to_int(jsmntok_t *tok, char *j)
Destructively extracts an int from a jsmn token.
Definition: jsmn_parser.c:42
JSON parser.
Definition: jsmn.h:75
#define log_error(fmt,...)
Definition: logging.h:101
struct json_state(* jsmn_initializer)(struct json_state *state, int index)
Typedef for a json_state initializer, used when iterating over lists of objects.
Definition: jsmn_parser.h:223
static jsmn_parsing_fn get_parse_fn(char *key, int parent_type)
Returns the function to parse a given key.
Definition: jsmn_parser.c:235
int parse_jsmn_obj(jsmntok_t **tok, char *j, struct json_state *state, struct json_state **saved)
Parses a single JSMN object utilizing the provided (global) key map.
Definition: jsmn_parser.c:358
int parse_jsmn_obj_list(jsmntok_t **tok, char *j, struct json_state *state, struct json_state **saved, jsmn_initializer init)
Parses an array of JSMN objects.
Definition: jsmn_parser.c:318
struct json_state * next
Definition: jsmn_parser.h:52
#define ASSERT_JSMN_TYPE(tok, toktype, j)
Asserts that the type of the current token is the provided type, and logs an error if that is not the...
Definition: jsmn_parser.h:39
int start
Definition: jsmn.h:63
General-purpose function to interact with JSMN library, and create objects (potentially with circular...
void * get_root_jsmn_obj()
Returns the initial object passed into the JSON parser.
Definition: jsmn_parser.c:92
#define MAX_RETRIES
The maximum number of times that a PARSE_FN can return 1 before an error is raised.
Definition: jsmn_parser.c:168
void jsmn_init(jsmn_parser *parser)
Create JSON parser over an array of tokens.
Definition: jsmn.c:331
int parse_file_into_obj(const char *filename, void *obj, struct key_mapping *km)
Using the provided functions, parses the JSON present in 'filename' and stores the resulting object i...
Definition: jsmn_parser.c:135
int end
Definition: jsmn.h:64
void * data
The object currently under construction.
Definition: jsmn_parser.h:50
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, unsigned int num_tokens)
Run JSON parser.
Definition: jsmn.c:173
static int retry_saved(struct json_state **saved, char *j)
Retries tokens which have been deferred.
Definition: jsmn_parser.c:256
int parse_str_into_obj(char *contents, void *obj, struct key_mapping *km)
Using the provided functions, parses the JSON present in in the provided string and stores the result...
Definition: jsmn_parser.c:171
#define log(level, fmt,...)
Log at a custom level.
Definition: logging.h:147
static void * global_obj
The object which is pased into the JSON parser to be filled.
Definition: jsmn_parser.c:87
int jsmn_ignore_obj(jsmntok_t **tok, char *j, struct json_state *in, struct json_state **saved)
Definition: jsmn_parser.c:106
jsmntok_t * tok
When saving state, provides a linked-list.
Definition: jsmn_parser.h:53
static const char tokens[256]
Definition: http_parser.c:208
state
Definition: http_parser.c:298