Dumb-ways-to-memorize
2D game
jsmn.c
Go to the documentation of this file.
1 #include "jsmn.h"
2 
3 /**
4  * Allocates a fresh unused token from the token pull.
5  */
7  jsmntok_t *tokens, size_t num_tokens) {
8  jsmntok_t *tok;
9  if (parser->toknext >= num_tokens) {
10  return NULL;
11  }
12  tok = &tokens[parser->toknext++];
13  tok->start = tok->end = -1;
14  tok->size = 0;
15 #ifdef JSMN_PARENT_LINKS
16  tok->parent = -1;
17 #endif
18  return tok;
19 }
20 
21 /**
22  * Fills token type and boundaries.
23  */
24 static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
25  int start, int end) {
26  token->type = type;
27  token->start = start;
28  token->end = end;
29  token->size = 0;
30 }
31 
32 /**
33  * Fills next available token with JSON primitive.
34  */
35 static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
36  size_t len, jsmntok_t *tokens, size_t num_tokens) {
37  jsmntok_t *token;
38  int start;
39 
40  start = parser->pos;
41 
42  for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
43  switch (js[parser->pos]) {
44 #ifndef JSMN_STRICT
45  /* In strict mode primitive must be followed by "," or "}" or "]" */
46  case ':':
47 #endif
48  case '\t' : case '\r' : case '\n' : case ' ' :
49  case ',' : case ']' : case '}' :
50  goto found;
51  }
52  if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
53  parser->pos = start;
54  return JSMN_ERROR_INVAL;
55  }
56  }
57 #ifdef JSMN_STRICT
58  /* In strict mode primitive must be followed by a comma/object/array */
59  parser->pos = start;
60  return JSMN_ERROR_PART;
61 #endif
62 
63 found:
64  if (tokens == NULL) {
65  parser->pos--;
66  return 0;
67  }
68  token = jsmn_alloc_token(parser, tokens, num_tokens);
69  if (token == NULL) {
70  parser->pos = start;
71  return JSMN_ERROR_NOMEM;
72  }
73  jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
74 #ifdef JSMN_PARENT_LINKS
75  token->parent = parser->toksuper;
76 #endif
77  parser->pos--;
78  return 0;
79 }
80 
81 /**
82  * Fills next token with JSON string.
83  */
84 static int jsmn_parse_string(jsmn_parser *parser, const char *js,
85  size_t len, jsmntok_t *tokens, size_t num_tokens) {
86  jsmntok_t *token;
87 
88  int start = parser->pos;
89 
90  parser->pos++;
91 
92  /* Skip starting quote */
93  for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
94  char c = js[parser->pos];
95 
96  /* Quote: end of string */
97  if (c == '\"') {
98  if (tokens == NULL) {
99  return 0;
100  }
101  token = jsmn_alloc_token(parser, tokens, num_tokens);
102  if (token == NULL) {
103  parser->pos = start;
104  return JSMN_ERROR_NOMEM;
105  }
106  jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
107 #ifdef JSMN_PARENT_LINKS
108  token->parent = parser->toksuper;
109 #endif
110  return 0;
111  }
112 
113  /* Backslash: Quoted symbol expected */
114  if (c == '\\' && parser->pos + 1 < len) {
115  int i;
116  parser->pos++;
117  switch (js[parser->pos]) {
118  /* Allowed escaped symbols */
119  case '\"': case '/' : case '\\' : case 'b' :
120  case 'f' : case 'r' : case 'n' : case 't' :
121  break;
122  /* Allows escaped symbol \uXXXX */
123  case 'u':
124  parser->pos++;
125  for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
126  /* If it isn't a hex character we have an error */
127  if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
128  (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
129  (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
130  parser->pos = start;
131  return JSMN_ERROR_INVAL;
132  }
133  parser->pos++;
134  }
135  parser->pos--;
136  break;
137  /* Unexpected symbol */
138  default:
139  parser->pos = start;
140  return JSMN_ERROR_INVAL;
141  }
142  }
143  }
144  parser->pos = start;
145  return JSMN_ERROR_PART;
146 }
147 
148 /**
149  * Parse JSON string and fill tokens.
150  */
151 int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
152  jsmntok_t *tokens, unsigned int num_tokens) {
153  int r;
154  int i;
155  jsmntok_t *token;
156  int count = parser->toknext;
157 
158  for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
159  char c;
160  jsmntype_t type;
161 
162  c = js[parser->pos];
163  switch (c) {
164  case '{': case '[':
165  count++;
166  if (tokens == NULL) {
167  break;
168  }
169  token = jsmn_alloc_token(parser, tokens, num_tokens);
170  if (token == NULL)
171  return JSMN_ERROR_NOMEM;
172  if (parser->toksuper != -1) {
173  tokens[parser->toksuper].size++;
174 #ifdef JSMN_PARENT_LINKS
175  token->parent = parser->toksuper;
176 #endif
177  }
178  token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
179  token->start = parser->pos;
180  parser->toksuper = parser->toknext - 1;
181  break;
182  case '}': case ']':
183  if (tokens == NULL)
184  break;
185  type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
186 #ifdef JSMN_PARENT_LINKS
187  if (parser->toknext < 1) {
188  return JSMN_ERROR_INVAL;
189  }
190  token = &tokens[parser->toknext - 1];
191  for (;;) {
192  if (token->start != -1 && token->end == -1) {
193  if (token->type != type) {
194  return JSMN_ERROR_INVAL;
195  }
196  token->end = parser->pos + 1;
197  parser->toksuper = token->parent;
198  break;
199  }
200  if (token->parent == -1) {
201  break;
202  }
203  token = &tokens[token->parent];
204  }
205 #else
206  for (i = parser->toknext - 1; i >= 0; i--) {
207  token = &tokens[i];
208  if (token->start != -1 && token->end == -1) {
209  if (token->type != type) {
210  return JSMN_ERROR_INVAL;
211  }
212  parser->toksuper = -1;
213  token->end = parser->pos + 1;
214  break;
215  }
216  }
217  /* Error if unmatched closing bracket */
218  if (i == -1) return JSMN_ERROR_INVAL;
219  for (; i >= 0; i--) {
220  token = &tokens[i];
221  if (token->start != -1 && token->end == -1) {
222  parser->toksuper = i;
223  break;
224  }
225  }
226 #endif
227  break;
228  case '\"':
229  r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
230  if (r < 0) return r;
231  count++;
232  if (parser->toksuper != -1 && tokens != NULL)
233  tokens[parser->toksuper].size++;
234  break;
235  case '\t' : case '\r' : case '\n' : case ' ':
236  break;
237  case ':':
238  parser->toksuper = parser->toknext - 1;
239  break;
240  case ',':
241  if (tokens != NULL && parser->toksuper != -1 &&
242  tokens[parser->toksuper].type != JSMN_ARRAY &&
243  tokens[parser->toksuper].type != JSMN_OBJECT) {
244 #ifdef JSMN_PARENT_LINKS
245  parser->toksuper = tokens[parser->toksuper].parent;
246 #else
247  for (i = parser->toknext - 1; i >= 0; i--) {
248  if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
249  if (tokens[i].start != -1 && tokens[i].end == -1) {
250  parser->toksuper = i;
251  break;
252  }
253  }
254  }
255 #endif
256  }
257  break;
258 #ifdef JSMN_STRICT
259  /* In strict mode primitives are: numbers and booleans */
260  case '-': case '0': case '1' : case '2': case '3' : case '4':
261  case '5': case '6': case '7' : case '8': case '9':
262  case 't': case 'f': case 'n' :
263  /* And they must not be keys of the object */
264  if (tokens != NULL && parser->toksuper != -1) {
265  jsmntok_t *t = &tokens[parser->toksuper];
266  if (t->type == JSMN_OBJECT ||
267  (t->type == JSMN_STRING && t->size != 0)) {
268  return JSMN_ERROR_INVAL;
269  }
270  }
271 #else
272  /* In non-strict mode every unquoted value is a primitive */
273  default:
274 #endif
275  r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
276  if (r < 0) return r;
277  count++;
278  if (parser->toksuper != -1 && tokens != NULL)
279  tokens[parser->toksuper].size++;
280  break;
281 
282 #ifdef JSMN_STRICT
283  /* Unexpected char in strict mode */
284  default:
285  return JSMN_ERROR_INVAL;
286 #endif
287  }
288  }
289 
290  if (tokens != NULL) {
291  for (i = parser->toknext - 1; i >= 0; i--) {
292  /* Unmatched opened object or array */
293  if (tokens[i].start != -1 && tokens[i].end == -1) {
294  return JSMN_ERROR_PART;
295  }
296  }
297  }
298 
299  return count;
300 }
301 
302 /**
303  * Creates a new parser based over a given buffer with an array of tokens
304  * available.
305  */
306 void jsmn_init(jsmn_parser *parser) {
307  parser->pos = 0;
308  parser->toknext = 0;
309  parser->toksuper = -1;
310 }
311 
Definition: jsmn.h:40
jsmntype_t
Definition: jsmn.h:17
static jsmntok_t * jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens, size_t num_tokens)
Definition: jsmn.c:6
unsigned int toknext
Definition: jsmn.h:56
jsmntype_t type
Definition: jsmn.h:41
static int jsmn_parse_string(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens)
Definition: jsmn.c:84
int toksuper
Definition: jsmn.h:57
int start
Definition: jsmn.h:42
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, unsigned int num_tokens)
Definition: jsmn.c:151
static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens)
Definition: jsmn.c:35
int end
Definition: jsmn.h:43
void jsmn_init(jsmn_parser *parser)
Definition: jsmn.c:306
int size
Definition: jsmn.h:44
static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, int start, int end)
Definition: jsmn.c:24
unsigned int pos
Definition: jsmn.h:55