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