]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ntp/libjsmn/jsmn.c
Update llvm/clang to r241361.
[FreeBSD/FreeBSD.git] / contrib / ntp / libjsmn / jsmn.c
1 #include <stdlib.h>
2 #include <string.h>
3
4 #include "jsmn.h"
5
6 /**
7  * Allocates a fresh unused token from the token pull.
8  */
9 static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, 
10                 jsmntok_t *tokens, size_t num_tokens) {
11         jsmntok_t *tok;
12         if ((size_t)parser->toknext >= num_tokens) {
13                 return NULL;
14         }
15         tok = &tokens[parser->toknext++];
16         tok->start = tok->end = -1;
17         tok->size = 0;
18 #ifdef JSMN_PARENT_LINKS
19         tok->parent = -1;
20 #endif
21         return tok;
22 }
23
24 /**
25  * Fills token type and boundaries.
26  */
27 static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, 
28                             int start, int end) {
29         token->type = type;
30         token->start = start;
31         token->end = end;
32         token->size = 0;
33 }
34
35 /**
36  * Fills next available token with JSON primitive.
37  */
38 static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
39                 jsmntok_t *tokens, size_t num_tokens) {
40         jsmntok_t *token;
41         int start;
42
43         start = parser->pos;
44
45         for (; js[parser->pos] != '\0'; parser->pos++) {
46                 switch (js[parser->pos]) {
47 #ifndef JSMN_STRICT
48                         /* In strict mode primitive must be followed by "," or "}" or "]" */
49                         case ':':
50 #endif
51                         case '\t' : case '\r' : case '\n' : case ' ' :
52                         case ','  : case ']'  : case '}' :
53                                 goto found;
54                 }
55                 if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
56                         parser->pos = start;
57                         return JSMN_ERROR_INVAL;
58                 }
59         }
60 #ifdef JSMN_STRICT
61         /* In strict mode primitive must be followed by a comma/object/array */
62         parser->pos = start;
63         return JSMN_ERROR_PART;
64 #endif
65
66 found:
67         token = jsmn_alloc_token(parser, tokens, num_tokens);
68         if (token == NULL) {
69                 parser->pos = start;
70                 return JSMN_ERROR_NOMEM;
71         }
72         jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
73 #ifdef JSMN_PARENT_LINKS
74         token->parent = parser->toksuper;
75 #endif
76         parser->pos--;
77         return JSMN_SUCCESS;
78 }
79
80 /**
81  * Filsl next token with JSON string.
82  */
83 static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
84                 jsmntok_t *tokens, size_t num_tokens) {
85         jsmntok_t *token;
86
87         int start = parser->pos;
88
89         parser->pos++;
90
91         /* Skip starting quote */
92         for (; js[parser->pos] != '\0'; parser->pos++) {
93                 char c = js[parser->pos];
94
95                 /* Quote: end of string */
96                 if (c == '\"') {
97                         token = jsmn_alloc_token(parser, tokens, num_tokens);
98                         if (token == NULL) {
99                                 parser->pos = start;
100                                 return JSMN_ERROR_NOMEM;
101                         }
102                         jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
103 #ifdef JSMN_PARENT_LINKS
104                         token->parent = parser->toksuper;
105 #endif
106                         return JSMN_SUCCESS;
107                 }
108
109                 /* Backslash: Quoted symbol expected */
110                 if (c == '\\') {
111                         int i = 0;
112
113                         parser->pos++;
114                         switch (js[parser->pos]) {
115                                 /* Allowed escaped symbols */
116                                 case '\"': case '/' : case '\\' : case 'b' :
117                                 case 'f' : case 'r' : case 'n'  : case 't' :
118                                         break;
119                                 /* Allows escaped symbol \uXXXX */
120                                 case 'u':
121                                         parser->pos++;
122                                         for(; i < 4 && js[parser->pos] != '\0'; i++) {
123                                                 /* If it isn't a hex character we have an error */
124                                                 if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
125                                                                         (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
126                                                                         (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
127                                                         parser->pos = start;
128                                                         return JSMN_ERROR_INVAL;
129                                                 }
130                                                 parser->pos++;
131                                         }
132                                         parser->pos--;
133                                         break;
134                                 /* Unexpected symbol */
135                                 default:
136                                         parser->pos = start;
137                                         return JSMN_ERROR_INVAL;
138                         }
139                 }
140         }
141         parser->pos = start;
142         return JSMN_ERROR_PART;
143 }
144
145 /**
146  * Parse JSON string and fill tokens.
147  */
148 jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, jsmntok_t *tokens, 
149                 unsigned int num_tokens) {
150         jsmnerr_t r;
151         int i;
152         jsmntok_t *token;
153
154         for (; js[parser->pos] != '\0'; parser->pos++) {
155                 char c;
156                 jsmntype_t type;
157
158                 c = js[parser->pos];
159                 switch (c) {
160                         case '{': case '[':
161                                 token = jsmn_alloc_token(parser, tokens, num_tokens);
162                                 if (token == NULL)
163                                         return JSMN_ERROR_NOMEM;
164                                 if (parser->toksuper != -1) {
165                                         tokens[parser->toksuper].size++;
166 #ifdef JSMN_PARENT_LINKS
167                                         token->parent = parser->toksuper;
168 #endif
169                                 }
170                                 token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
171                                 token->start = parser->pos;
172                                 parser->toksuper = parser->toknext - 1;
173                                 break;
174                         case '}': case ']':
175                                 type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
176 #ifdef JSMN_PARENT_LINKS
177                                 if (parser->toknext < 1) {
178                                         return JSMN_ERROR_INVAL;
179                                 }
180                                 token = &tokens[parser->toknext - 1];
181                                 for (;;) {
182                                         if (token->start != -1 && token->end == -1) {
183                                                 if (token->type != type) {
184                                                         return JSMN_ERROR_INVAL;
185                                                 }
186                                                 token->end = parser->pos + 1;
187                                                 parser->toksuper = token->parent;
188                                                 break;
189                                         }
190                                         if (token->parent == -1) {
191                                                 break;
192                                         }
193                                         token = &tokens[token->parent];
194                                 }
195 #else
196                                 for (i = parser->toknext - 1; i >= 0; i--) {
197                                         token = &tokens[i];
198                                         if (token->start != -1 && token->end == -1) {
199                                                 if (token->type != type) {
200                                                         return JSMN_ERROR_INVAL;
201                                                 }
202                                                 parser->toksuper = -1;
203                                                 token->end = parser->pos + 1;
204                                                 break;
205                                         }
206                                 }
207                                 /* Error if unmatched closing bracket */
208                                 if (i == -1) return JSMN_ERROR_INVAL;
209                                 for (; i >= 0; i--) {
210                                         token = &tokens[i];
211                                         if (token->start != -1 && token->end == -1) {
212                                                 parser->toksuper = i;
213                                                 break;
214                                         }
215                                 }
216 #endif
217                                 break;
218                         case '\"':
219                                 r = jsmn_parse_string(parser, js, tokens, num_tokens);
220                                 if (r < 0) return r;
221                                 if (parser->toksuper != -1)
222                                         tokens[parser->toksuper].size++;
223                                 break;
224                         case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ': 
225                                 break;
226 #ifdef JSMN_STRICT
227                         /* In strict mode primitives are: numbers and booleans */
228                         case '-': case '0': case '1' : case '2': case '3' : case '4':
229                         case '5': case '6': case '7' : case '8': case '9':
230                         case 't': case 'f': case 'n' :
231 #else
232                         /* In non-strict mode every unquoted value is a primitive */
233                         default:
234 #endif
235                                 r = jsmn_parse_primitive(parser, js, tokens, num_tokens);
236                                 if (r < 0) return r;
237                                 if (parser->toksuper != -1)
238                                         tokens[parser->toksuper].size++;
239                                 break;
240
241 #ifdef JSMN_STRICT
242                         /* Unexpected char in strict mode */
243                         default:
244                                 return JSMN_ERROR_INVAL;
245 #endif
246
247                 }
248         }
249
250         for (i = parser->toknext - 1; i >= 0; i--) {
251                 /* Unmatched opened object or array */
252                 if (tokens[i].start != -1 && tokens[i].end == -1) {
253                         return JSMN_ERROR_PART;
254                 }
255         }
256
257         return JSMN_SUCCESS;
258 }
259
260 /**
261  * Creates a new parser based over a given  buffer with an array of tokens 
262  * available.
263  */
264 void jsmn_init(jsmn_parser *parser) {
265         parser->pos = 0;
266         parser->toknext = 0;
267         parser->toksuper = -1;
268 }
269