]>
diplodocus.org Git - nmh/blob - thirdparty/jsmn/jsmn.c
6 * Allocates a fresh unused token from the token pull.
8 static jsmntok_t
*jsmn_alloc_token(jsmn_parser
*parser
,
9 jsmntok_t
*tokens
, size_t num_tokens
) {
11 if (parser
->toknext
>= num_tokens
) {
14 tok
= &tokens
[parser
->toknext
++];
15 tok
->start
= tok
->end
= -1;
17 #ifdef JSMN_PARENT_LINKS
24 * Fills token type and boundaries.
26 static void jsmn_fill_token(jsmntok_t
*token
, jsmntype_t type
,
35 * Fills next available token with JSON primitive.
37 static jsmnerr_t
jsmn_parse_primitive(jsmn_parser
*parser
, const char *js
,
38 size_t len
, jsmntok_t
*tokens
, size_t num_tokens
) {
44 for (; parser
->pos
< len
&& js
[parser
->pos
] != '\0'; parser
->pos
++) {
45 switch (js
[parser
->pos
]) {
47 /* In strict mode primitive must be followed by "," or "}" or "]" */
50 case '\t' : case '\r' : case '\n' : case ' ' :
51 case ',' : case ']' : case '}' :
54 if (js
[parser
->pos
] < 32 || js
[parser
->pos
] >= 127) {
56 return JSMN_ERROR_INVAL
;
60 /* In strict mode primitive must be followed by a comma/object/array */
62 return JSMN_ERROR_PART
;
70 token
= jsmn_alloc_token(parser
, tokens
, num_tokens
);
73 return JSMN_ERROR_NOMEM
;
75 jsmn_fill_token(token
, JSMN_PRIMITIVE
, start
, parser
->pos
);
76 #ifdef JSMN_PARENT_LINKS
77 token
->parent
= parser
->toksuper
;
84 * Filsl next token with JSON string.
86 static jsmnerr_t
jsmn_parse_string(jsmn_parser
*parser
, const char *js
,
87 size_t len
, jsmntok_t
*tokens
, size_t num_tokens
) {
90 int start
= parser
->pos
;
94 /* Skip starting quote */
95 for (; parser
->pos
< len
&& js
[parser
->pos
] != '\0'; parser
->pos
++) {
96 char c
= js
[parser
->pos
];
98 /* Quote: end of string */
100 if (tokens
== NULL
) {
103 token
= jsmn_alloc_token(parser
, tokens
, num_tokens
);
106 return JSMN_ERROR_NOMEM
;
108 jsmn_fill_token(token
, JSMN_STRING
, start
+1, parser
->pos
);
109 #ifdef JSMN_PARENT_LINKS
110 token
->parent
= parser
->toksuper
;
115 /* Backslash: Quoted symbol expected */
116 if (c
== '\\' && parser
->pos
+ 1 < len
) {
119 switch (js
[parser
->pos
]) {
120 /* Allowed escaped symbols */
121 case '\"': case '/' : case '\\' : case 'b' :
122 case 'f' : case 'r' : case 'n' : case 't' :
124 /* Allows escaped symbol \uXXXX */
127 for(i
= 0; i
< 4 && parser
->pos
< len
&& js
[parser
->pos
] != '\0'; i
++) {
128 /* If it isn't a hex character we have an error */
129 if(!((js
[parser
->pos
] >= 48 && js
[parser
->pos
] <= 57) || /* 0-9 */
130 (js
[parser
->pos
] >= 65 && js
[parser
->pos
] <= 70) || /* A-F */
131 (js
[parser
->pos
] >= 97 && js
[parser
->pos
] <= 102))) { /* a-f */
133 return JSMN_ERROR_INVAL
;
139 /* Unexpected symbol */
142 return JSMN_ERROR_INVAL
;
147 return JSMN_ERROR_PART
;
151 * Parse JSON string and fill tokens.
153 jsmnerr_t
jsmn_parse(jsmn_parser
*parser
, const char *js
, size_t len
,
154 jsmntok_t
*tokens
, unsigned int num_tokens
) {
160 for (; parser
->pos
< len
&& js
[parser
->pos
] != '\0'; parser
->pos
++) {
168 if (tokens
== NULL
) {
171 token
= jsmn_alloc_token(parser
, tokens
, num_tokens
);
173 return JSMN_ERROR_NOMEM
;
174 if (parser
->toksuper
!= -1) {
175 tokens
[parser
->toksuper
].size
++;
176 #ifdef JSMN_PARENT_LINKS
177 token
->parent
= parser
->toksuper
;
180 token
->type
= (c
== '{' ? JSMN_OBJECT
: JSMN_ARRAY
);
181 token
->start
= parser
->pos
;
182 parser
->toksuper
= parser
->toknext
- 1;
187 type
= (c
== '}' ? JSMN_OBJECT
: JSMN_ARRAY
);
188 #ifdef JSMN_PARENT_LINKS
189 if (parser
->toknext
< 1) {
190 return JSMN_ERROR_INVAL
;
192 token
= &tokens
[parser
->toknext
- 1];
194 if (token
->start
!= -1 && token
->end
== -1) {
195 if (token
->type
!= type
) {
196 return JSMN_ERROR_INVAL
;
198 token
->end
= parser
->pos
+ 1;
199 parser
->toksuper
= token
->parent
;
202 if (token
->parent
== -1) {
205 token
= &tokens
[token
->parent
];
208 for (i
= parser
->toknext
- 1; i
>= 0; i
--) {
210 if (token
->start
!= -1 && token
->end
== -1) {
211 if (token
->type
!= type
) {
212 return JSMN_ERROR_INVAL
;
214 parser
->toksuper
= -1;
215 token
->end
= parser
->pos
+ 1;
219 /* Error if unmatched closing bracket */
220 if (i
== -1) return JSMN_ERROR_INVAL
;
221 for (; i
>= 0; i
--) {
223 if (token
->start
!= -1 && token
->end
== -1) {
224 parser
->toksuper
= i
;
231 r
= jsmn_parse_string(parser
, js
, len
, tokens
, num_tokens
);
234 if (parser
->toksuper
!= -1 && tokens
!= NULL
)
235 tokens
[parser
->toksuper
].size
++;
237 case '\t' : case '\r' : case '\n' : case ' ':
240 parser
->toksuper
= parser
->toknext
- 1;
243 if (tokens
!= NULL
&&
244 tokens
[parser
->toksuper
].type
!= JSMN_ARRAY
&&
245 tokens
[parser
->toksuper
].type
!= JSMN_OBJECT
) {
246 #ifdef JSMN_PARENT_LINKS
247 parser
->toksuper
= tokens
[parser
->toksuper
].parent
;
249 for (i
= parser
->toknext
- 1; i
>= 0; i
--) {
250 if (tokens
[i
].type
== JSMN_ARRAY
|| tokens
[i
].type
== JSMN_OBJECT
) {
251 if (tokens
[i
].start
!= -1 && tokens
[i
].end
== -1) {
252 parser
->toksuper
= i
;
261 /* In strict mode primitives are: numbers and booleans */
262 case '-': case '0': case '1' : case '2': case '3' : case '4':
263 case '5': case '6': case '7' : case '8': case '9':
264 case 't': case 'f': case 'n' :
265 /* And they must not be keys of the object */
266 if (tokens
!= NULL
) {
267 jsmntok_t
*t
= &tokens
[parser
->toksuper
];
268 if (t
->type
== JSMN_OBJECT
||
269 (t
->type
== JSMN_STRING
&& t
->size
!= 0)) {
270 return JSMN_ERROR_INVAL
;
274 /* In non-strict mode every unquoted value is a primitive */
277 r
= jsmn_parse_primitive(parser
, js
, len
, tokens
, num_tokens
);
280 if (parser
->toksuper
!= -1 && tokens
!= NULL
)
281 tokens
[parser
->toksuper
].size
++;
285 /* Unexpected char in strict mode */
287 return JSMN_ERROR_INVAL
;
292 for (i
= parser
->toknext
- 1; i
>= 0; i
--) {
293 /* Unmatched opened object or array */
294 if (tokens
[i
].start
!= -1 && tokens
[i
].end
== -1) {
295 return JSMN_ERROR_PART
;
303 * Creates a new parser based over a given buffer with an array of tokens
306 void jsmn_init(jsmn_parser
*parser
) {
309 parser
->toksuper
= -1;