4 * Allocates a fresh unused token from the token pool.
6 static jsmntok_t
*jsmn_alloc_token(jsmn_parser
*parser
,
7 jsmntok_t
*tokens
, size_t num_tokens
) {
9 if (parser
->toknext
>= num_tokens
) {
12 tok
= &tokens
[parser
->toknext
++];
13 tok
->start
= tok
->end
= -1;
15 #ifdef JSMN_PARENT_LINKS
22 * Fills token type and boundaries.
24 static void jsmn_fill_token(jsmntok_t
*token
, jsmntype_t type
,
33 * Fills next available token with JSON primitive.
35 static int jsmn_parse_primitive(jsmn_parser
*parser
, const char *js
,
36 size_t len
, jsmntok_t
*tokens
, size_t num_tokens
) {
42 for (; parser
->pos
< len
&& js
[parser
->pos
] != '\0'; parser
->pos
++) {
43 switch (js
[parser
->pos
]) {
45 /* In strict mode primitive must be followed by "," or "}" or "]" */
48 case '\t' : case '\r' : case '\n' : case ' ' :
49 case ',' : case ']' : case '}' :
52 if (js
[parser
->pos
] < 32 || js
[parser
->pos
] >= 127) {
54 return JSMN_ERROR_INVAL
;
58 /* In strict mode primitive must be followed by a comma/object/array */
60 return JSMN_ERROR_PART
;
68 token
= jsmn_alloc_token(parser
, tokens
, num_tokens
);
71 return JSMN_ERROR_NOMEM
;
73 jsmn_fill_token(token
, JSMN_PRIMITIVE
, start
, parser
->pos
);
74 #ifdef JSMN_PARENT_LINKS
75 token
->parent
= parser
->toksuper
;
82 * Fills next token with JSON string.
84 static int jsmn_parse_string(jsmn_parser
*parser
, const char *js
,
85 size_t len
, jsmntok_t
*tokens
, size_t num_tokens
) {
88 int start
= parser
->pos
;
92 /* Skip starting quote */
93 for (; parser
->pos
< len
&& js
[parser
->pos
] != '\0'; parser
->pos
++) {
94 char c
= js
[parser
->pos
];
96 /* Quote: end of string */
101 token
= jsmn_alloc_token(parser
, tokens
, num_tokens
);
104 return JSMN_ERROR_NOMEM
;
106 jsmn_fill_token(token
, JSMN_STRING
, start
+1, parser
->pos
);
107 #ifdef JSMN_PARENT_LINKS
108 token
->parent
= parser
->toksuper
;
113 /* Backslash: Quoted symbol expected */
114 if (c
== '\\' && parser
->pos
+ 1 < len
) {
117 switch (js
[parser
->pos
]) {
118 /* Allowed escaped symbols */
119 case '\"': case '/' : case '\\' : case 'b' :
120 case 'f' : case 'r' : case 'n' : case 't' :
122 /* Allows escaped symbol \uXXXX */
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 */
131 return JSMN_ERROR_INVAL
;
137 /* Unexpected symbol */
140 return JSMN_ERROR_INVAL
;
145 return JSMN_ERROR_PART
;
149 * Parse JSON string and fill tokens.
151 int jsmn_parse(jsmn_parser
*parser
, const char *js
, size_t len
,
152 jsmntok_t
*tokens
, unsigned int num_tokens
) {
156 int count
= parser
->toknext
;
158 for (; parser
->pos
< len
&& js
[parser
->pos
] != '\0'; parser
->pos
++) {
166 if (tokens
== NULL
) {
169 token
= jsmn_alloc_token(parser
, tokens
, num_tokens
);
171 return JSMN_ERROR_NOMEM
;
172 if (parser
->toksuper
!= -1) {
173 if (tokens
[parser
->toksuper
].type
== JSMN_OBJECT
) {
174 /* Object keys must be strings, not objects or arrays */
175 return JSMN_ERROR_INVAL
;
177 tokens
[parser
->toksuper
].size
++;
178 #ifdef JSMN_PARENT_LINKS
179 token
->parent
= parser
->toksuper
;
182 token
->type
= (c
== '{' ? JSMN_OBJECT
: JSMN_ARRAY
);
183 token
->start
= parser
->pos
;
184 parser
->toksuper
= parser
->toknext
- 1;
189 type
= (c
== '}' ? JSMN_OBJECT
: JSMN_ARRAY
);
190 #ifdef JSMN_PARENT_LINKS
191 if (parser
->toknext
< 1) {
192 return JSMN_ERROR_INVAL
;
194 token
= &tokens
[parser
->toknext
- 1];
196 if (token
->start
!= -1 && token
->end
== -1) {
197 if (token
->type
!= type
) {
198 return JSMN_ERROR_INVAL
;
200 token
->end
= parser
->pos
+ 1;
201 parser
->toksuper
= token
->parent
;
204 if (token
->parent
== -1) {
205 if(token
->type
!= type
|| parser
->toksuper
== -1) {
206 return JSMN_ERROR_INVAL
;
210 token
= &tokens
[token
->parent
];
213 for (i
= parser
->toknext
- 1; i
>= 0; i
--) {
215 if (token
->start
!= -1 && token
->end
== -1) {
216 if (token
->type
!= type
) {
217 return JSMN_ERROR_INVAL
;
219 parser
->toksuper
= -1;
220 token
->end
= parser
->pos
+ 1;
224 /* Error if unmatched closing bracket */
225 if (i
== -1) return JSMN_ERROR_INVAL
;
226 for (; i
>= 0; i
--) {
228 if (token
->start
!= -1 && token
->end
== -1) {
229 parser
->toksuper
= i
;
236 r
= jsmn_parse_string(parser
, js
, len
, tokens
, num_tokens
);
239 if (parser
->toksuper
!= -1 && tokens
!= NULL
)
240 tokens
[parser
->toksuper
].size
++;
242 case '\t' : case '\r' : case '\n' : case ' ':
245 parser
->toksuper
= parser
->toknext
- 1;
248 if (tokens
!= NULL
&& parser
->toksuper
!= -1 &&
249 tokens
[parser
->toksuper
].type
!= JSMN_ARRAY
&&
250 tokens
[parser
->toksuper
].type
!= JSMN_OBJECT
) {
251 #ifdef JSMN_PARENT_LINKS
252 parser
->toksuper
= tokens
[parser
->toksuper
].parent
;
254 for (i
= parser
->toknext
- 1; i
>= 0; i
--) {
255 if (tokens
[i
].type
== JSMN_ARRAY
|| tokens
[i
].type
== JSMN_OBJECT
) {
256 if (tokens
[i
].start
!= -1 && tokens
[i
].end
== -1) {
257 parser
->toksuper
= i
;
266 /* In strict mode primitives are: numbers and booleans */
267 case '-': case '0': case '1' : case '2': case '3' : case '4':
268 case '5': case '6': case '7' : case '8': case '9':
269 case 't': case 'f': case 'n' :
270 /* And they must not be keys of the object */
271 if (tokens
!= NULL
&& parser
->toksuper
!= -1) {
272 jsmntok_t
*t
= &tokens
[parser
->toksuper
];
273 if (t
->type
== JSMN_OBJECT
||
274 (t
->type
== JSMN_STRING
&& t
->size
!= 0)) {
275 return JSMN_ERROR_INVAL
;
279 /* In non-strict mode every unquoted value is a primitive */
282 r
= jsmn_parse_primitive(parser
, js
, len
, tokens
, num_tokens
);
285 if (parser
->toksuper
!= -1 && tokens
!= NULL
)
286 tokens
[parser
->toksuper
].size
++;
290 /* Unexpected char in strict mode */
292 return JSMN_ERROR_INVAL
;
297 if (tokens
!= NULL
) {
298 for (i
= parser
->toknext
- 1; i
>= 0; i
--) {
299 /* Unmatched opened object or array */
300 if (tokens
[i
].start
!= -1 && tokens
[i
].end
== -1) {
301 return JSMN_ERROR_PART
;
310 * Creates a new parser based over a given buffer with an array of tokens
313 void jsmn_init(jsmn_parser
*parser
) {
316 parser
->toksuper
= -1;