Spellforce-Spell-framework
Toggle main menu visibility
Loading...
Searching...
No Matches
jsmn.h
Go to the documentation of this file.
1
/*
2
* MIT License
3
*
4
* Copyright (c) 2010 Serge Zaitsev
5
*
6
* Permission is hereby granted, free of charge, to any person obtaining a copy
7
* of this software and associated documentation files (the "Software"), to deal
8
* in the Software without restriction, including without limitation the rights
9
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
* copies of the Software, and to permit persons to whom the Software is
11
* furnished to do so, subject to the following conditions:
12
*
13
* The above copyright notice and this permission notice shall be included in
14
* all copies or substantial portions of the Software.
15
*
16
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
* SOFTWARE.
23
*/
24
#ifndef JSMN_H
25
#define JSMN_H
26
27
#include <stddef.h>
28
29
#ifdef __cplusplus
30
extern
"C"
{
31
#endif
32
33
#ifdef JSMN_STATIC
34
#define JSMN_API static
35
#else
36
#define JSMN_API extern
37
#endif
38
46
typedef
enum
{
47
JSMN_UNDEFINED
= 0,
48
JSMN_OBJECT
= 1,
49
JSMN_ARRAY
= 2,
50
JSMN_STRING
= 3,
51
JSMN_PRIMITIVE
= 4
52
}
jsmntype_t
;
53
54
enum
jsmnerr
{
55
/* Not enough tokens were provided */
56
JSMN_ERROR_NOMEM
= -1,
57
/* Invalid character inside JSON string */
58
JSMN_ERROR_INVAL
= -2,
59
/* The string is not a full JSON packet, more bytes expected */
60
JSMN_ERROR_PART
= -3
61
};
62
69
typedef
struct
{
70
jsmntype_t
type
;
71
int
start
;
72
int
end
;
73
int
size
;
74
#ifdef JSMN_PARENT_LINKS
75
int
parent;
76
#endif
77
}
jsmntok_t
;
78
83
typedef
struct
{
84
unsigned
int
pos
;
/* offset in the JSON string */
85
unsigned
int
toknext
;
/* next token to allocate */
86
int
toksuper
;
/* superior token node, e.g. parent object or array */
87
}
jsmn_parser
;
88
92
JSMN_API
void
jsmn_init
(
jsmn_parser
*parser);
93
99
JSMN_API
int
jsmn_parse
(
jsmn_parser
*parser,
const
char
*js,
const
size_t
len,
100
jsmntok_t
*tokens,
const
unsigned
int
num_tokens);
101
102
#ifndef JSMN_HEADER
106
static
jsmntok_t
*jsmn_alloc_token(
jsmn_parser
*parser,
jsmntok_t
*tokens,
107
const
size_t
num_tokens) {
108
jsmntok_t
*tok;
109
if
(parser->
toknext
>= num_tokens) {
110
return
NULL;
111
}
112
tok = &tokens[parser->
toknext
++];
113
tok->
start
= tok->
end
= -1;
114
tok->
size
= 0;
115
#ifdef JSMN_PARENT_LINKS
116
tok->parent = -1;
117
#endif
118
return
tok;
119
}
120
124
static
void
jsmn_fill_token(
jsmntok_t
*token,
const
jsmntype_t
type,
125
const
int
start,
const
int
end) {
126
token->
type
= type;
127
token->
start
= start;
128
token->
end
= end;
129
token->
size
= 0;
130
}
131
135
static
int
jsmn_parse_primitive(
jsmn_parser
*parser,
const
char
*js,
136
const
size_t
len,
jsmntok_t
*tokens,
137
const
size_t
num_tokens) {
138
jsmntok_t
*token;
139
int
start;
140
141
start = parser->
pos
;
142
143
for
(; parser->
pos
< len && js[parser->
pos
] !=
'\0'
; parser->
pos
++) {
144
switch
(js[parser->
pos
]) {
145
#ifndef JSMN_STRICT
146
/* In strict mode primitive must be followed by "," or "}" or "]" */
147
case
':'
:
148
#endif
149
case
'\t'
:
150
case
'\r'
:
151
case
'\n'
:
152
case
' '
:
153
case
','
:
154
case
']'
:
155
case
'}'
:
156
goto
found;
157
}
158
if
(js[parser->
pos
] < 32 || js[parser->
pos
] >= 127) {
159
parser->
pos
= start;
160
return
JSMN_ERROR_INVAL
;
161
}
162
}
163
#ifdef JSMN_STRICT
164
/* In strict mode primitive must be followed by a comma/object/array */
165
parser->
pos
= start;
166
return
JSMN_ERROR_PART
;
167
#endif
168
169
found:
170
if
(tokens == NULL) {
171
parser->
pos
--;
172
return
0;
173
}
174
token = jsmn_alloc_token(parser, tokens, num_tokens);
175
if
(token == NULL) {
176
parser->
pos
= start;
177
return
JSMN_ERROR_NOMEM
;
178
}
179
jsmn_fill_token(token,
JSMN_PRIMITIVE
, start, parser->
pos
);
180
#ifdef JSMN_PARENT_LINKS
181
token->parent = parser->
toksuper
;
182
#endif
183
parser->
pos
--;
184
return
0;
185
}
186
190
static
int
jsmn_parse_string(
jsmn_parser
*parser,
const
char
*js,
191
const
size_t
len,
jsmntok_t
*tokens,
192
const
size_t
num_tokens) {
193
jsmntok_t
*token;
194
195
int
start = parser->
pos
;
196
197
parser->
pos
++;
198
199
/* Skip starting quote */
200
for
(; parser->
pos
< len && js[parser->
pos
] !=
'\0'
; parser->
pos
++) {
201
char
c = js[parser->
pos
];
202
203
/* Quote: end of string */
204
if
(c ==
'\"'
) {
205
if
(tokens == NULL) {
206
return
0;
207
}
208
token = jsmn_alloc_token(parser, tokens, num_tokens);
209
if
(token == NULL) {
210
parser->
pos
= start;
211
return
JSMN_ERROR_NOMEM
;
212
}
213
jsmn_fill_token(token,
JSMN_STRING
, start + 1, parser->
pos
);
214
#ifdef JSMN_PARENT_LINKS
215
token->parent = parser->
toksuper
;
216
#endif
217
return
0;
218
}
219
220
/* Backslash: Quoted symbol expected */
221
if
(c ==
'\\'
&& parser->
pos
+ 1 < len) {
222
int
i;
223
parser->
pos
++;
224
switch
(js[parser->
pos
]) {
225
/* Allowed escaped symbols */
226
case
'\"'
:
227
case
'/'
:
228
case
'\\'
:
229
case
'b'
:
230
case
'f'
:
231
case
'r'
:
232
case
'n'
:
233
case
't'
:
234
break
;
235
/* Allows escaped symbol \uXXXX */
236
case
'u'
:
237
parser->
pos
++;
238
for
(i = 0; i < 4 && parser->
pos
< len && js[parser->
pos
] !=
'\0'
;
239
i++) {
240
/* If it isn't a hex character we have an error */
241
if
(!((js[parser->
pos
] >= 48 && js[parser->
pos
] <= 57) ||
/* 0-9 */
242
(js[parser->
pos
] >= 65 && js[parser->
pos
] <= 70) ||
/* A-F */
243
(js[parser->
pos
] >= 97 && js[parser->
pos
] <= 102))) {
/* a-f */
244
parser->
pos
= start;
245
return
JSMN_ERROR_INVAL
;
246
}
247
parser->
pos
++;
248
}
249
parser->
pos
--;
250
break
;
251
/* Unexpected symbol */
252
default
:
253
parser->
pos
= start;
254
return
JSMN_ERROR_INVAL
;
255
}
256
}
257
}
258
parser->
pos
= start;
259
return
JSMN_ERROR_PART
;
260
}
261
265
JSMN_API
int
jsmn_parse
(
jsmn_parser
*parser,
const
char
*js,
const
size_t
len,
266
jsmntok_t
*tokens,
const
unsigned
int
num_tokens) {
267
int
r;
268
int
i;
269
jsmntok_t
*token;
270
int
count = parser->
toknext
;
271
272
for
(; parser->
pos
< len && js[parser->
pos
] !=
'\0'
; parser->
pos
++) {
273
char
c;
274
jsmntype_t
type;
275
276
c = js[parser->
pos
];
277
switch
(c) {
278
case
'{'
:
279
case
'['
:
280
count++;
281
if
(tokens == NULL) {
282
break
;
283
}
284
token = jsmn_alloc_token(parser, tokens, num_tokens);
285
if
(token == NULL) {
286
return
JSMN_ERROR_NOMEM
;
287
}
288
if
(parser->
toksuper
!= -1) {
289
jsmntok_t
*t = &tokens[parser->
toksuper
];
290
#ifdef JSMN_STRICT
291
/* In strict mode an object or array can't become a key */
292
if
(t->
type
==
JSMN_OBJECT
) {
293
return
JSMN_ERROR_INVAL
;
294
}
295
#endif
296
t->
size
++;
297
#ifdef JSMN_PARENT_LINKS
298
token->parent = parser->
toksuper
;
299
#endif
300
}
301
token->
type
= (c ==
'{'
?
JSMN_OBJECT
:
JSMN_ARRAY
);
302
token->
start
= parser->
pos
;
303
parser->
toksuper
= parser->
toknext
- 1;
304
break
;
305
case
'}'
:
306
case
']'
:
307
if
(tokens == NULL) {
308
break
;
309
}
310
type = (c ==
'}'
?
JSMN_OBJECT
:
JSMN_ARRAY
);
311
#ifdef JSMN_PARENT_LINKS
312
if
(parser->
toknext
< 1) {
313
return
JSMN_ERROR_INVAL
;
314
}
315
token = &tokens[parser->
toknext
- 1];
316
for
(;;) {
317
if
(token->
start
!= -1 && token->
end
== -1) {
318
if
(token->
type
!= type) {
319
return
JSMN_ERROR_INVAL
;
320
}
321
token->
end
= parser->
pos
+ 1;
322
parser->
toksuper
= token->parent;
323
break
;
324
}
325
if
(token->parent == -1) {
326
if
(token->
type
!= type || parser->
toksuper
== -1) {
327
return
JSMN_ERROR_INVAL
;
328
}
329
break
;
330
}
331
token = &tokens[token->parent];
332
}
333
#else
334
for
(i = parser->
toknext
- 1; i >= 0; i--) {
335
token = &tokens[i];
336
if
(token->
start
!= -1 && token->
end
== -1) {
337
if
(token->
type
!= type) {
338
return
JSMN_ERROR_INVAL
;
339
}
340
parser->
toksuper
= -1;
341
token->
end
= parser->
pos
+ 1;
342
break
;
343
}
344
}
345
/* Error if unmatched closing bracket */
346
if
(i == -1) {
347
return
JSMN_ERROR_INVAL
;
348
}
349
for
(; i >= 0; i--) {
350
token = &tokens[i];
351
if
(token->
start
!= -1 && token->
end
== -1) {
352
parser->
toksuper
= i;
353
break
;
354
}
355
}
356
#endif
357
break
;
358
case
'\"'
:
359
r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
360
if
(r < 0) {
361
return
r;
362
}
363
count++;
364
if
(parser->
toksuper
!= -1 && tokens != NULL) {
365
tokens[parser->
toksuper
].
size
++;
366
}
367
break
;
368
case
'\t'
:
369
case
'\r'
:
370
case
'\n'
:
371
case
' '
:
372
break
;
373
case
':'
:
374
parser->
toksuper
= parser->
toknext
- 1;
375
break
;
376
case
','
:
377
if
(tokens != NULL && parser->
toksuper
!= -1 &&
378
tokens[parser->
toksuper
].
type
!=
JSMN_ARRAY
&&
379
tokens[parser->
toksuper
].
type
!=
JSMN_OBJECT
) {
380
#ifdef JSMN_PARENT_LINKS
381
parser->
toksuper
= tokens[parser->
toksuper
].parent;
382
#else
383
for
(i = parser->
toknext
- 1; i >= 0; i--) {
384
if
(tokens[i].type ==
JSMN_ARRAY
|| tokens[i].type ==
JSMN_OBJECT
) {
385
if
(tokens[i].start != -1 && tokens[i].end == -1) {
386
parser->
toksuper
= i;
387
break
;
388
}
389
}
390
}
391
#endif
392
}
393
break
;
394
#ifdef JSMN_STRICT
395
/* In strict mode primitives are: numbers and booleans */
396
case
'-'
:
397
case
'0'
:
398
case
'1'
:
399
case
'2'
:
400
case
'3'
:
401
case
'4'
:
402
case
'5'
:
403
case
'6'
:
404
case
'7'
:
405
case
'8'
:
406
case
'9'
:
407
case
't'
:
408
case
'f'
:
409
case
'n'
:
410
/* And they must not be keys of the object */
411
if
(tokens != NULL && parser->
toksuper
!= -1) {
412
const
jsmntok_t
*t = &tokens[parser->
toksuper
];
413
if
(t->
type
==
JSMN_OBJECT
||
414
(t->
type
==
JSMN_STRING
&& t->
size
!= 0)) {
415
return
JSMN_ERROR_INVAL
;
416
}
417
}
418
#else
419
/* In non-strict mode every unquoted value is a primitive */
420
default
:
421
#endif
422
r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
423
if
(r < 0) {
424
return
r;
425
}
426
count++;
427
if
(parser->
toksuper
!= -1 && tokens != NULL) {
428
tokens[parser->
toksuper
].
size
++;
429
}
430
break
;
431
432
#ifdef JSMN_STRICT
433
/* Unexpected char in strict mode */
434
default
:
435
return
JSMN_ERROR_INVAL
;
436
#endif
437
}
438
}
439
440
if
(tokens != NULL) {
441
for
(i = parser->
toknext
- 1; i >= 0; i--) {
442
/* Unmatched opened object or array */
443
if
(tokens[i].start != -1 && tokens[i].end == -1) {
444
return
JSMN_ERROR_PART
;
445
}
446
}
447
}
448
449
return
count;
450
}
451
456
JSMN_API
void
jsmn_init
(
jsmn_parser
*parser) {
457
parser->
pos
= 0;
458
parser->
toknext
= 0;
459
parser->
toksuper
= -1;
460
}
461
462
#endif
/* JSMN_HEADER */
463
464
#ifdef __cplusplus
465
}
466
#endif
467
468
#endif
/* JSMN_H */
jsmntype_t
jsmntype_t
Definition
jsmn.h:46
JSMN_PRIMITIVE
@ JSMN_PRIMITIVE
Definition
jsmn.h:51
JSMN_OBJECT
@ JSMN_OBJECT
Definition
jsmn.h:48
JSMN_UNDEFINED
@ JSMN_UNDEFINED
Definition
jsmn.h:47
JSMN_ARRAY
@ JSMN_ARRAY
Definition
jsmn.h:49
JSMN_STRING
@ JSMN_STRING
Definition
jsmn.h:50
jsmn_init
void jsmn_init(jsmn_parser *parser)
Definition
jsmn.h:456
JSMN_API
#define JSMN_API
Definition
jsmn.h:36
jsmn_parse
int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, jsmntok_t *tokens, const unsigned int num_tokens)
Definition
jsmn.h:265
jsmnerr
jsmnerr
Definition
jsmn.h:54
JSMN_ERROR_INVAL
@ JSMN_ERROR_INVAL
Definition
jsmn.h:58
JSMN_ERROR_PART
@ JSMN_ERROR_PART
Definition
jsmn.h:60
JSMN_ERROR_NOMEM
@ JSMN_ERROR_NOMEM
Definition
jsmn.h:56
jsmn_parser
Definition
jsmn.h:83
jsmn_parser::pos
unsigned int pos
Definition
jsmn.h:84
jsmn_parser::toksuper
int toksuper
Definition
jsmn.h:86
jsmn_parser::toknext
unsigned int toknext
Definition
jsmn.h:85
jsmntok_t
Definition
jsmn.h:69
jsmntok_t::start
int start
Definition
jsmn.h:71
jsmntok_t::size
int size
Definition
jsmn.h:73
jsmntok_t::end
int end
Definition
jsmn.h:72
jsmntok_t::type
jsmntype_t type
Definition
jsmn.h:70
src
internal
core
jsmn.h
Generated by
1.17.0