]> 4ch.mooo.com Git - 16.git/blob - src/lib/jsmn/farjsmn.c
a2acc5613d6a47917d2241d23b42d20c71662b25
[16.git] / src / lib / jsmn / farjsmn.c
1 #include <stdlib.h>
2 #include <stdio.h>      //fprintf for noisy debugging wwww
3
4 #include "farjsmn.h"
5
6 /**
7  * Allocates a fresh unused token from the token pull.
8  */
9 static jsmntok_t huge *jsmn_alloc_token(jsmn_parser huge *parser,
10                 jsmntok_t huge *tokens, size_t num_tokens) {
11         jsmntok_t huge *tok;
12         if (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 huge *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 huge *parser, const char huge *js,
39                 size_t len, jsmntok_t huge *tokens, size_t num_tokens) {
40         jsmntok_t huge *token;
41         int start;
42
43         start = parser->pos;
44
45         for (; parser->pos < len && 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         if (tokens == NULL) {
68                 parser->pos--;
69                 return 0;
70         }
71         token = jsmn_alloc_token(parser, tokens, num_tokens);
72         if (token == NULL) {
73                 parser->pos = start;
74                 return JSMN_ERROR_NOMEM;
75         }
76         jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
77 #ifdef JSMN_PARENT_LINKS
78         token->parent = parser->toksuper;
79 #endif
80         parser->pos--;
81         return 0;
82 }
83
84 /**
85  * Filsl next token with JSON string.
86  */
87 static jsmnerr_t jsmn_parse_string(jsmn_parser huge *parser, const char huge *js,
88                 size_t len, jsmntok_t huge *tokens, size_t num_tokens) {
89         jsmntok_t huge *token;
90
91         int start = parser->pos;
92
93         parser->pos++;
94
95         /* Skip starting quote */
96         for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
97                 char c = js[parser->pos];
98
99                 /* Quote: end of string */
100                 if (c == '\"') {
101                         if (tokens == NULL) {
102                                 return 0;
103                         }
104                         token = jsmn_alloc_token(parser, tokens, num_tokens);
105                         if (token == NULL) {
106                                 parser->pos = start;
107                                 return JSMN_ERROR_NOMEM;
108                         }
109                         jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
110 #ifdef JSMN_PARENT_LINKS
111                         token->parent = parser->toksuper;
112 #endif
113                         return 0;
114                 }
115
116                 /* Backslash: Quoted symbol expected */
117                 if (c == '\\' && parser->pos + 1 < len) {
118                         int i;
119                         parser->pos++;
120                         switch (js[parser->pos]) {
121                                 /* Allowed escaped symbols */
122                                 case '\"': case '/' : case '\\' : case 'b' :
123                                 case 'f' : case 'r' : case 'n'  : case 't' :
124                                         break;
125                                 /* Allows escaped symbol \uXXXX */
126                                 case 'u':
127                                         parser->pos++;
128                                         for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
129                                                 /* If it isn't a hex character we have an error */
130                                                 if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
131                                                                         (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
132                                                                         (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
133                                                         parser->pos = start;
134                                                         return JSMN_ERROR_INVAL;
135                                                 }
136                                                 parser->pos++;
137                                         }
138                                         parser->pos--;
139                                         break;
140                                 /* Unexpected symbol */
141                                 default:
142                                         parser->pos = start;
143                                         return JSMN_ERROR_INVAL;
144                         }
145                 }
146         }
147         parser->pos = start;
148         return JSMN_ERROR_PART;
149 }
150
151 /**
152  * Parse JSON string and fill tokens.
153  */
154 jsmnerr_t jsmn_parse(jsmn_parser huge *parser, const char huge *js, size_t len,
155                 jsmntok_t huge *tokens, unsigned int num_tokens) {
156         jsmnerr_t r;
157         int i;
158         jsmntok_t huge *token;
159         int count = 0;
160         static unsigned long pee=0;
161
162         for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
163                 char c;
164                 jsmntype_t type;
165
166 fprintf(stdout, "%lu    %c      count=%u        i=%d    nt=%u\n", pee, js[parser->pos], count, i, num_tokens);
167 //fprintf(stdout, "token->start=%d\n", token->start);
168 pee++;
169
170                 c = js[parser->pos];
171                 switch (c) {
172                         case '{': case '[':
173                                 count++;
174                                 if (tokens == NULL) {
175                                         break;
176                                 }
177                                 token = jsmn_alloc_token(parser, tokens, num_tokens);
178                                 if (token == NULL)
179                                         return JSMN_ERROR_NOMEM;
180                                 if (parser->toksuper != -1) {
181                                         tokens[parser->toksuper].size++;
182 #ifdef JSMN_PARENT_LINKS
183                                         token->parent = parser->toksuper;
184 #endif
185                                 }
186                                 token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
187                                 token->start = parser->pos;
188                                 parser->toksuper = parser->toknext - 1;
189                                 break;
190                         case '}': case ']':
191                                 if (tokens == NULL)
192                                         break;
193                                 type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
194 #ifdef JSMN_PARENT_LINKS
195                                 if (parser->toknext < 1) {
196                                         return JSMN_ERROR_INVAL;
197                                 }
198                                 token = &tokens[parser->toknext - 1];
199                                 for (;;) {
200                                         if (token->start != -1 && token->end == -1) {
201                                                 if (token->type != type) {
202                                                         return JSMN_ERROR_INVAL;
203                                                 }
204                                                 token->end = parser->pos + 1;
205                                                 parser->toksuper = token->parent;
206                                                 break;
207                                         }
208                                         if (token->parent == -1) {
209                                                 break;
210                                         }
211                                         token = &tokens[token->parent];
212                                 }
213 #else
214                                 for (i = parser->toknext - 1; i >= 0; i--) {
215                                         token = &tokens[i];
216                                         if (token->start != -1 && token->end == -1) {
217                                                 if (token->type != type) {
218                                                         return JSMN_ERROR_INVAL;
219                                                 }
220                                                 parser->toksuper = -1;
221                                                 token->end = parser->pos + 1;
222                                                 break;
223                                         }
224                                 }
225                                 /* Error if unmatched closing bracket */
226                                 if (i == -1) return JSMN_ERROR_INVAL;
227                                 for (; i >= 0; i--) {
228                                         token = &tokens[i];
229                                         if (token->start != -1 && token->end == -1) {
230                                                 parser->toksuper = i;
231                                                 break;
232                                         }
233                                 }
234 #endif
235                                 break;
236                         case '\"':
237                                 r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
238                                 if (r < 0) return r;
239                                 count++;
240                                 if (parser->toksuper != -1 && tokens != NULL)
241                                         tokens[parser->toksuper].size++;
242                                 break;
243                         case '\t' : case '\r' : case '\n' : case ' ':
244                                 break;
245                         case ':':
246                                 parser->toksuper = parser->toknext - 1;
247                                 break;
248                         case ',':
249                                 if (tokens != NULL &&
250                                                 tokens[parser->toksuper].type != JSMN_ARRAY &&
251                                                 tokens[parser->toksuper].type != JSMN_OBJECT) {
252 #ifdef JSMN_PARENT_LINKS
253                                         parser->toksuper = tokens[parser->toksuper].parent;
254 #else
255                                         for (i = parser->toknext - 1; i >= 0; i--) {
256                                                 if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
257                                                         if (tokens[i].start != -1 && tokens[i].end == -1) {
258                                                                 parser->toksuper = i;
259                                                                 break;
260                                                         }
261                                                 }
262                                         }
263 #endif
264                                 }
265                                 break;
266 #ifdef JSMN_STRICT
267                         /* In strict mode primitives are: numbers and booleans */
268                         case '-': case '0': case '1' : case '2': case '3' : case '4':
269                         case '5': case '6': case '7' : case '8': case '9':
270                         case 't': case 'f': case 'n' :
271                                 /* And they must not be keys of the object */
272                                 if (tokens != NULL) {
273                                         jsmntok_t huge *t = &tokens[parser->toksuper];
274                                         if (t->type == JSMN_OBJECT ||
275                                                         (t->type == JSMN_STRING && t->size != 0)) {
276                                                 return JSMN_ERROR_INVAL;
277                                         }
278                                 }
279 #else
280                         /* In non-strict mode every unquoted value is a primitive */
281                         default:
282 #endif
283                                 r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
284                                 if (r < 0) return r;
285                                 count++;
286                                 if (parser->toksuper != -1 && tokens != NULL)
287                                         tokens[parser->toksuper].size++;
288                                 break;
289
290 #ifdef JSMN_STRICT
291                         /* Unexpected char in strict mode */
292                         default:
293                                 return JSMN_ERROR_INVAL;
294 #endif
295                 }
296         }
297
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;
302                 }
303         }
304
305         return count;
306 }
307
308 /**
309  * Creates a new parser based over a given  buffer with an array of tokens
310  * available.
311  */
312 void jsmn_init(jsmn_parser huge *parser) {
313         parser->pos = 0;
314         parser->toknext = 0;
315         parser->toksuper = -1;
316 }
317