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