2104e8a73a67b442be4b3ce52b38f4269ece3aa7
[jansson.git] / src / load.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <ctype.h>
6 #include <assert.h>
7
8 #include <jansson.h>
9
10
11 #define JSON_TOKEN_INVALID         -1
12 #define JSON_TOKEN_EOF              0
13 #define JSON_TOKEN_STRING         256
14 #define JSON_TOKEN_NUMBER         257
15 #define JSON_TOKEN_TRUE           258
16 #define JSON_TOKEN_FALSE          259
17 #define JSON_TOKEN_NULL           260
18
19 typedef struct {
20     const char *input;
21     const char *start;
22     int token;
23     int line, column;
24     union {
25         char *string;
26         double number;
27     } value;
28 } json_lex;
29
30
31 /*** error reporting ***/
32
33 static void json_set_error(json_error_t *error, const json_lex *lex,
34                            const char *msg)
35 {
36     if(!error)
37         return;
38
39     if(*lex->start)
40     {
41         int n = (int)(lex->input - lex->start);
42         error->line = lex->line;
43         snprintf(error->text, JSON_ERROR_TEXT_LENGTH,
44                  "%s near '%.*s'", msg, n, lex->start);
45     }
46     else
47     {
48         snprintf(error->text, JSON_ERROR_TEXT_LENGTH,
49                  "%s near end of file", msg);
50     }
51 }
52
53
54 /*** lexical analyzer ***/
55
56 static void json_scan_string(json_lex *lex)
57 {
58     /* skip the " */
59     const char *p = lex->input + 1;
60     char *t;
61
62     lex->token = JSON_TOKEN_INVALID;
63
64     while(*p != '"') {
65         if(*p == '\0') {
66             /* unterminated string literal */
67             goto out;
68         }
69
70         if(0 <= *p && *p <= 31) {
71             /* control character */
72             goto out;
73         }
74         else if(*p == '\\') {
75             p++;
76             if(*p == 'u') {
77                 p++;
78                 for(int i = 0; i < 4; i++, p++) {
79                     if(!isxdigit(*p))
80                         goto out;
81                 }
82             }
83             if(*p == '"' || *p == '\\' || *p == '/' || *p == 'b' ||
84                *p == 'f' || *p == 'n' || *p == 'r' || *p == 't')
85                 p++;
86             else
87                 goto out;
88         }
89         else
90             p++;
91     }
92
93     /* the actual value is at most of the same length as the source
94        string */
95     lex->value.string = malloc(p - lex->start);
96     if(!lex->value.string) {
97         /* this is not very nice, since TOKEN_INVALID is returned */
98         goto out;
99     }
100
101     /* the target */
102     t = lex->value.string;
103
104     p = lex->input + 1;
105     while(*p != '"') {
106         if(*p == '\\') {
107             p++;
108             if(*p == 'u') {
109                 /* TODO: \uXXXX not supported yet */
110                 free(lex->value.string);
111                 lex->value.string = NULL;
112                 goto out;
113             } else {
114                 switch(*p) {
115                     case '"': case '\\': case '/':
116                         *t = *p; break;
117                     case 'b': *t = '\b'; break;
118                     case 'f': *t = '\f'; break;
119                     case 'n': *t = '\n'; break;
120                     case 'r': *t = '\r'; break;
121                     case 't': *t = '\t'; break;
122                     default: assert(0);
123                 }
124             }
125         }
126         else
127             *t = *p;
128
129         t++;
130         p++;
131     }
132     /* skip the " */
133     p++;
134
135     *t = '\0';
136     lex->token = JSON_TOKEN_STRING;
137
138 out:
139     lex->input = p;
140 }
141
142 static void json_scan_number(json_lex *lex)
143 {
144     const char *p = lex->input;
145     char *end;
146
147     lex->token = JSON_TOKEN_INVALID;
148
149     if(*p == '-')
150         p++;
151
152     if(*p == '0')
153         p++;
154     else /* *p != '0' */ {
155         p++;
156         while(isdigit(*p))
157             p++;
158     }
159
160     if(*p == '.') {
161         p++;
162         if(!isdigit(*(p++)))
163             goto out;
164
165         while(isdigit(*p))
166             p++;
167     }
168
169     if(*p == 'E' || *p == 'e') {
170         p++;
171         if(*p == '+' || *p == '-')
172             p++;
173
174         if(!isdigit(*(p++)))
175             goto out;
176
177         while(isdigit(*p))
178             p++;
179     }
180
181     lex->token = JSON_TOKEN_NUMBER;
182
183     lex->value.number = strtod(lex->start, &end);
184     assert(end == p);
185
186 out:
187     lex->input = p;
188 }
189
190 static int json_lex_scan(json_lex *lex)
191 {
192     char c;
193
194     if(lex->token == JSON_TOKEN_STRING) {
195       free(lex->value.string);
196       lex->value.string = NULL;
197     }
198
199     while(isspace(*lex->input)) {
200         if(*lex->input == '\n')
201             lex->line++;
202
203         lex->input++;
204     }
205
206     lex->start = lex->input;
207     c = *lex->input;
208
209     if(c == '\0')
210         lex->token = JSON_TOKEN_EOF;
211
212     else if(c == '{' || c == '}' || c == '[' || c == ']' ||
213             c == ':' || c == ',') {
214         lex->token = c;
215         lex->input++;
216     }
217
218     else if(c == '"')
219         json_scan_string(lex);
220
221     else if(isdigit(c) || c == '-')
222         json_scan_number(lex);
223
224     else if(isalpha(c)) {
225         /* eat up the whole identifier for clearer error messages */
226         int len;
227
228         while(isalpha(*lex->input))
229             lex->input++;
230         len = lex->input - lex->start;
231
232         if(strncmp(lex->start, "true", len) == 0)
233             lex->token = JSON_TOKEN_TRUE;
234         else if(strncmp(lex->start, "false", len) == 0)
235             lex->token = JSON_TOKEN_FALSE;
236         else if(strncmp(lex->start, "null", len) == 0)
237             lex->token = JSON_TOKEN_NULL;
238         else
239             lex->token = JSON_TOKEN_INVALID;
240     }
241
242     else {
243         lex->token = JSON_TOKEN_INVALID;
244         lex->input++;
245     }
246
247     return lex->token;
248 }
249
250 static int json_lex_init(json_lex *lex, const char *input)
251 {
252     lex->input = input;
253     lex->token = JSON_TOKEN_INVALID;
254     lex->line = 1;
255
256     json_lex_scan(lex);
257     return 0;
258 }
259
260 static void json_lex_close(json_lex *lex)
261 {
262     if(lex->token == JSON_TOKEN_STRING)
263         free(lex->value.string);
264 }
265
266
267 /*** parser ***/
268
269 static json_t *json_parse(json_lex *lex, json_error_t *error);
270
271 static json_t *json_parse_object(json_lex *lex, json_error_t *error)
272 {
273     json_t *object = json_object();
274     if(!object)
275         return NULL;
276
277     json_lex_scan(lex);
278     if(lex->token == '}')
279         return object;
280
281     while(lex->token) {
282         char *key;
283         json_t *value;
284
285         if(lex->token != JSON_TOKEN_STRING) {
286             json_set_error(error, lex, "string expected");
287             goto error;
288         }
289
290         key = strdup(lex->value.string);
291         if(!key)
292             return NULL;
293
294         json_lex_scan(lex);
295         if(lex->token != ':') {
296             json_set_error(error, lex, "':' expected");
297             goto error;
298         }
299
300         json_lex_scan(lex);
301
302         value = json_parse(lex, error);
303         if(!value)
304             goto error;
305
306         if(json_object_set(object, key, value)) {
307             json_decref(value);
308             goto error;
309         }
310
311         json_decref(value);
312         free(key);
313
314         if(lex->token != ',')
315             break;
316
317         json_lex_scan(lex);
318     }
319
320     if(lex->token != '}') {
321         json_set_error(error, lex, "'}' expected");
322         goto error;
323     }
324
325     return object;
326
327 error:
328     json_decref(object);
329     return NULL;
330 }
331
332 static json_t *json_parse_array(json_lex *lex, json_error_t *error)
333 {
334     json_t *array = json_array();
335     if(!array)
336         return NULL;
337
338     json_lex_scan(lex);
339     if(lex->token != ']') {
340         while(1) {
341             json_t *elem = json_parse(lex, error);
342             if(!elem)
343                 goto error;
344
345             if(json_array_append(array, elem)) {
346                 json_decref(elem);
347                 goto error;
348             }
349             json_decref(elem);
350
351             if(lex->token != ',')
352                 break;
353
354             json_lex_scan(lex);
355         }
356     }
357
358     if(lex->token != ']') {
359         json_set_error(error, lex, "']' expected");
360         goto error;
361     }
362
363     return array;
364
365 error:
366     json_decref(array);
367     return NULL;
368 }
369
370 static json_t *json_parse(json_lex *lex, json_error_t *error)
371 {
372     json_t *json;
373
374     switch(lex->token) {
375         case JSON_TOKEN_STRING: {
376             json = json_string(lex->value.string);
377             break;
378         }
379
380         case JSON_TOKEN_NUMBER: {
381             json = json_number(lex->value.number);
382             break;
383         }
384
385         case JSON_TOKEN_TRUE:
386             json = json_true();
387             break;
388
389         case JSON_TOKEN_FALSE:
390             json = json_false();
391             break;
392
393         case JSON_TOKEN_NULL:
394             json = json_null();
395             break;
396
397         case '{':
398           json = json_parse_object(lex, error);
399             break;
400
401         case '[':
402             json = json_parse_array(lex, error);
403             break;
404
405         case JSON_TOKEN_INVALID:
406             json_set_error(error, lex, "invalid token");
407             return NULL;
408
409         default:
410             json_set_error(error, lex, "unexpected token");
411             return NULL;
412     }
413
414     if(!json)
415         return NULL;
416
417     json_lex_scan(lex);
418     return json;
419 }
420
421 json_t *json_loads(const char *string, json_error_t *error)
422 {
423     json_lex lex;
424     json_t *result = NULL;
425
426     if(json_lex_init(&lex, string))
427         return NULL;
428
429     if(lex.token != '[' && lex.token != '{') {
430         json_set_error(error, &lex, "'[' or '{' expected");
431         goto out;
432     }
433
434     result = json_parse(&lex, error);
435     if(!result)
436         goto out;
437
438     if(lex.token != JSON_TOKEN_EOF) {
439         json_set_error(error, &lex, "end of file expected");
440         json_decref(result);
441         result = NULL;
442     }
443
444 out:
445     json_lex_close(&lex);
446     return result;
447 }