Streamify the loader
[profile/ivi/jansson.git] / src / load.c
1 #define _GNU_SOURCE
2 #include <ctype.h>
3 #include <errno.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdarg.h>
8 #include <unistd.h>
9 #include <assert.h>
10
11 #include <jansson.h>
12 #include "strbuffer.h"
13
14 #define TOKEN_INVALID         -1
15 #define TOKEN_EOF              0
16 #define TOKEN_STRING         256
17 #define TOKEN_INTEGER        257
18 #define TOKEN_REAL           258
19 #define TOKEN_TRUE           259
20 #define TOKEN_FALSE          260
21 #define TOKEN_NULL           261
22
23 /* read one byte from stream, return EOF on end of file */
24 typedef int (*get_func)(void *data);
25
26 /* return non-zero if end of file has been reached */
27 typedef int (*eof_func)(void *data);
28
29 typedef struct {
30     get_func get;
31     eof_func eof;
32     void *data;
33     char buffer[5];
34     int buffer_pos;
35 } stream_t;
36
37
38 typedef struct {
39     stream_t stream;
40     strbuffer_t saved_text;
41     int token;
42     int line, column;
43     union {
44         char *string;
45         int integer;
46         double real;
47     } value;
48 } lex_t;
49
50
51 /*** error reporting ***/
52
53 static void error_set(json_error_t *error, const lex_t *lex,
54                       const char *msg, ...)
55 {
56     va_list ap;
57     char text[JSON_ERROR_TEXT_LENGTH];
58
59     if(!error)
60         return;
61
62     va_start(ap, msg);
63     vsnprintf(text, JSON_ERROR_TEXT_LENGTH, msg, ap);
64     va_end(ap);
65
66     if(lex)
67     {
68         const char *saved_text = strbuffer_value(&lex->saved_text);
69         error->line = lex->line;
70         if(saved_text && saved_text[0])
71         {
72             snprintf(error->text, JSON_ERROR_TEXT_LENGTH,
73                      "%s near '%s'", text, saved_text);
74         }
75         else
76         {
77             snprintf(error->text, JSON_ERROR_TEXT_LENGTH,
78                      "%s near end of file", text);
79         }
80     }
81     else
82     {
83         error->line = -1;
84         snprintf(error->text, JSON_ERROR_TEXT_LENGTH, "%s", text);
85     }
86 }
87
88
89 /*** lexical analyzer ***/
90
91 void stream_init(stream_t *stream, get_func get, eof_func eof, void *data)
92 {
93     stream->get = get;
94     stream->eof = eof;
95     stream->data = data;
96     stream->buffer[0] = '\0';
97     stream->buffer_pos = 0;
98 }
99
100 static char stream_get(stream_t *stream)
101 {
102     if(!stream->buffer[stream->buffer_pos])
103     {
104         stream->buffer[0] = stream->get(stream->data);
105         stream->buffer_pos = 0;
106     }
107
108     return (char)stream->buffer[stream->buffer_pos++];
109 }
110
111 static void stream_unget(stream_t *stream, char c)
112 {
113     assert(stream->buffer_pos > 0);
114     stream->buffer_pos--;
115     assert(stream->buffer[stream->buffer_pos] == (unsigned char)c);
116 }
117
118
119 static int lex_get(lex_t *lex)
120 {
121     return stream_get(&lex->stream);
122 }
123
124 static int lex_eof(lex_t *lex)
125 {
126     return lex->stream.eof(lex->stream.data);
127 }
128
129 static void lex_save(lex_t *lex, char c)
130 {
131     strbuffer_append_byte(&lex->saved_text, c);
132 }
133
134 static int lex_get_save(lex_t *lex)
135 {
136     char c = stream_get(&lex->stream);
137     lex_save(lex, c);
138     return c;
139 }
140
141 static void lex_unget_unsave(lex_t *lex, char c)
142 {
143     char d;
144     stream_unget(&lex->stream, c);
145     d = strbuffer_pop(&lex->saved_text);
146     assert(c == d);
147 }
148
149 static void lex_scan_string(lex_t *lex)
150 {
151     char c;
152     const char *p;
153     char *t;
154
155     lex->token = TOKEN_INVALID;
156
157     /* skip the " */
158     c = lex_get_save(lex);
159
160     while(c != '"') {
161         if(c == EOF && lex_eof(lex))
162             goto out;
163
164         else if(0 <= c && c <= 0x1F) {
165             /* control character */
166             lex_unget_unsave(lex, c);
167             goto out;
168         }
169
170         else if(c == '\\') {
171             c = lex_get_save(lex);
172             if(c == 'u') {
173                 c = lex_get_save(lex);
174                 for(int i = 0; i < 4; i++) {
175                     if(!isxdigit(c)) {
176                         lex_unget_unsave(lex, c);
177                         goto out;
178                     }
179                     c = lex_get_save(lex);
180                 }
181             }
182             else if(c == '"' || c == '\\' || c == '/' || c == 'b' ||
183                     c == 'f' || c == 'n' || c == 'r' || c == 't')
184                 c = lex_get_save(lex);
185             else {
186                 lex_unget_unsave(lex, c);
187                 goto out;
188             }
189         }
190         else
191             c = lex_get_save(lex);
192     }
193
194     /* the actual value is at most of the same length as the source
195        string, because:
196          - shortcut escapes (e.g. "\t") (length 2) are converted to 1 byte
197          - a single \uXXXX escape (length 6) is converted to at most 3 bytes
198          - two \uXXXX escapes (length 12) forming an UTF-16 surrogate pair
199            are converted to 4 bytes
200     */
201     lex->value.string = malloc(lex->saved_text.length + 1);
202     if(!lex->value.string) {
203         /* this is not very nice, since TOKEN_INVALID is returned */
204         goto out;
205     }
206
207     /* the target */
208     t = lex->value.string;
209
210     /* + 1 to skip the " */
211     p = strbuffer_value(&lex->saved_text) + 1;
212
213     while(*p != '"') {
214         if(*p == '\\') {
215             p++;
216             if(*p == 'u') {
217                 /* TODO: \uXXXX not supported yet */
218                 free(lex->value.string);
219                 lex->value.string = NULL;
220                 goto out;
221             } else {
222                 switch(*p) {
223                     case '"': case '\\': case '/':
224                         *t = *p; break;
225                     case 'b': *t = '\b'; break;
226                     case 'f': *t = '\f'; break;
227                     case 'n': *t = '\n'; break;
228                     case 'r': *t = '\r'; break;
229                     case 't': *t = '\t'; break;
230                     default: assert(0);
231                 }
232             }
233         }
234         else
235             *t = *p;
236
237         t++;
238         p++;
239     }
240     *t = '\0';
241     lex->token = TOKEN_STRING;
242
243 out:
244     return;
245 }
246
247 static void lex_scan_number(lex_t *lex, char c)
248 {
249     const char *saved_text;
250     char *end;
251
252     lex->token = TOKEN_INVALID;
253
254     if(c == '-')
255         c = lex_get_save(lex);
256
257     if(c == '0') {
258         c = lex_get_save(lex);
259         if(isdigit(c)) {
260             lex_unget_unsave(lex, c);
261             goto out;
262         }
263     }
264     else /* c != '0' */ {
265         c = lex_get_save(lex);
266         while(isdigit(c))
267             c = lex_get_save(lex);
268     }
269
270     if(c != '.' && c != 'E' && c != 'e') {
271         lex_unget_unsave(lex, c);
272         lex->token = TOKEN_INTEGER;
273
274         saved_text = strbuffer_value(&lex->saved_text);
275         lex->value.integer = strtol(saved_text, &end, 10);
276         assert(end == saved_text + lex->saved_text.length);
277
278         return;
279     }
280
281     if(c == '.') {
282         c = lex_get(lex);
283         if(!isdigit(c))
284             goto out;
285         lex_save(lex, c);
286
287         c = lex_get_save(lex);
288         while(isdigit(c))
289             c = lex_get_save(lex);
290     }
291
292     if(c == 'E' || c == 'e') {
293         c = lex_get_save(lex);
294         if(c == '+' || c == '-')
295             c = lex_get_save(lex);
296
297         if(!isdigit(c)) {
298             lex_unget_unsave(lex, c);
299             goto out;
300         }
301
302         c = lex_get_save(lex);
303         while(isdigit(c))
304             c = lex_get_save(lex);
305     }
306
307     lex_unget_unsave(lex, c);
308     lex->token = TOKEN_REAL;
309
310     saved_text = strbuffer_value(&lex->saved_text);
311     lex->value.real = strtod(saved_text, &end);
312     assert(end == saved_text + lex->saved_text.length);
313
314 out:
315     return;
316 }
317
318 static int lex_scan(lex_t *lex)
319 {
320     char c;
321
322     strbuffer_clear(&lex->saved_text);
323
324     if(lex->token == TOKEN_STRING) {
325       free(lex->value.string);
326       lex->value.string = NULL;
327     }
328
329     c = lex_get(lex);
330     while(c == ' ' || c == '\t' || c == '\n' || c == '\r')
331     {
332         if(c == '\n')
333             lex->line++;
334
335         c = lex_get(lex);
336     }
337
338     if(c == EOF && lex_eof(lex)) {
339         lex->token = TOKEN_EOF;
340         goto out;
341     }
342
343     lex_save(lex, c);
344
345     if(c == '{' || c == '}' || c == '[' || c == ']' || c == ':' || c == ',')
346         lex->token = c;
347
348     else if(c == '"')
349         lex_scan_string(lex);
350
351     else if(isdigit(c) || c == '-')
352         lex_scan_number(lex, c);
353
354     else if(isupper(c) || islower(c)) {
355         /* eat up the whole identifier for clearer error messages */
356         const char *saved_text;
357
358         c = lex_get_save(lex);
359         while(isupper(c) || islower(c))
360             c = lex_get_save(lex);
361         lex_unget_unsave(lex, c);
362
363         saved_text = strbuffer_value(&lex->saved_text);
364
365         if(strcmp(saved_text, "true") == 0)
366             lex->token = TOKEN_TRUE;
367         else if(strcmp(saved_text, "false") == 0)
368             lex->token = TOKEN_FALSE;
369         else if(strcmp(saved_text, "null") == 0)
370             lex->token = TOKEN_NULL;
371         else
372             lex->token = TOKEN_INVALID;
373     }
374
375     else
376         lex->token = TOKEN_INVALID;
377
378 out:
379     return lex->token;
380 }
381
382 static int lex_init(lex_t *lex, get_func get, eof_func eof, void *data)
383 {
384     stream_init(&lex->stream, get, eof, data);
385     if(strbuffer_init(&lex->saved_text))
386         return -1;
387
388     lex->token = TOKEN_INVALID;
389     lex->line = 1;
390
391     return 0;
392 }
393
394 static void lex_close(lex_t *lex)
395 {
396     if(lex->token == TOKEN_STRING)
397         free(lex->value.string);
398 }
399
400
401 /*** parser ***/
402
403 static json_t *parse_value(lex_t *lex, json_error_t *error);
404
405 static json_t *parse_object(lex_t *lex, json_error_t *error)
406 {
407     json_t *object = json_object();
408     if(!object)
409         return NULL;
410
411     lex_scan(lex);
412     if(lex->token == '}')
413         return object;
414
415     while(1) {
416         char *key;
417         json_t *value;
418
419         if(lex->token != TOKEN_STRING) {
420             error_set(error, lex, "string or '}' expected");
421             goto error;
422         }
423
424         key = strdup(lex->value.string);
425         if(!key)
426             return NULL;
427
428         lex_scan(lex);
429         if(lex->token != ':') {
430             free(key);
431             error_set(error, lex, "':' expected");
432             goto error;
433         }
434
435         lex_scan(lex);
436         value = parse_value(lex, error);
437         if(!value) {
438             free(key);
439             goto error;
440         }
441
442         if(json_object_set(object, key, value)) {
443             free(key);
444             json_decref(value);
445             goto error;
446         }
447
448         json_decref(value);
449         free(key);
450
451         lex_scan(lex);
452         if(lex->token != ',')
453             break;
454
455         lex_scan(lex);
456     }
457
458     if(lex->token != '}') {
459         error_set(error, lex, "'}' expected");
460         goto error;
461     }
462
463     return object;
464
465 error:
466     json_decref(object);
467     return NULL;
468 }
469
470 static json_t *parse_array(lex_t *lex, json_error_t *error)
471 {
472     json_t *array = json_array();
473     if(!array)
474         return NULL;
475
476     lex_scan(lex);
477     if(lex->token == ']')
478         return array;
479
480     while(lex->token) {
481         json_t *elem = parse_value(lex, error);
482         if(!elem)
483             goto error;
484
485         if(json_array_append(array, elem)) {
486             json_decref(elem);
487             goto error;
488         }
489         json_decref(elem);
490
491         lex_scan(lex);
492         if(lex->token != ',')
493             break;
494
495         lex_scan(lex);
496     }
497
498     if(lex->token != ']') {
499         error_set(error, lex, "']' expected");
500         goto error;
501     }
502
503     return array;
504
505 error:
506     json_decref(array);
507     return NULL;
508 }
509
510 static json_t *parse_value(lex_t *lex, json_error_t *error)
511 {
512     json_t *json;
513
514     switch(lex->token) {
515         case TOKEN_STRING: {
516             json = json_string(lex->value.string);
517             break;
518         }
519
520         case TOKEN_INTEGER: {
521             json = json_integer(lex->value.integer);
522             break;
523         }
524
525         case TOKEN_REAL: {
526             json = json_real(lex->value.real);
527             break;
528         }
529
530         case TOKEN_TRUE:
531             json = json_true();
532             break;
533
534         case TOKEN_FALSE:
535             json = json_false();
536             break;
537
538         case TOKEN_NULL:
539             json = json_null();
540             break;
541
542         case '{':
543           json = parse_object(lex, error);
544             break;
545
546         case '[':
547             json = parse_array(lex, error);
548             break;
549
550         case TOKEN_INVALID:
551             error_set(error, lex, "invalid token");
552             return NULL;
553
554         default:
555             error_set(error, lex, "unexpected token");
556             return NULL;
557     }
558
559     if(!json)
560         return NULL;
561
562     return json;
563 }
564
565 json_t *parse_json(lex_t *lex, json_error_t *error)
566 {
567     lex_scan(lex);
568
569     if(lex->token != '[' && lex->token != '{') {
570         error_set(error, lex, "'[' or '{' expected");
571         return NULL;
572     }
573
574     return parse_value(lex, error);
575 }
576
577 json_t *json_load(const char *path, json_error_t *error)
578 {
579     json_t *result;
580     FILE *fp;
581
582     fp = fopen(path, "r");
583     if(!fp)
584     {
585         error_set(error, NULL, "unable to open %s: %s",
586                   path, strerror(errno));
587         return NULL;
588     }
589
590     result = json_loadf(fp, error);
591
592     fclose(fp);
593     return result;
594 }
595
596 typedef struct
597 {
598     const char *data;
599     int pos;
600 } string_data_t;
601
602 static int string_get(void *data)
603 {
604     char c;
605     string_data_t *stream = (string_data_t *)data;
606     c = stream->data[stream->pos++];
607     if(c == '\0')
608         return EOF;
609     else
610         return c;
611 }
612
613 static int string_eof(void *data)
614 {
615     string_data_t *stream = (string_data_t *)data;
616     return (stream->data[stream->pos] == '\0');
617 }
618
619 json_t *json_loads(const char *string, json_error_t *error)
620 {
621     lex_t lex;
622     json_t *result;
623
624     string_data_t stream_data = {
625         .data = string,
626         .pos = 0
627     };
628
629     if(lex_init(&lex, string_get, string_eof, (void *)&stream_data))
630         return NULL;
631
632     result = parse_json(&lex, error);
633     if(!result)
634         goto out;
635
636     lex_scan(&lex);
637     if(lex.token != TOKEN_EOF) {
638         error_set(error, &lex, "end of file expected");
639         json_decref(result);
640         result = NULL;
641     }
642
643 out:
644     lex_close(&lex);
645     return result;
646 }
647
648 json_t *json_loadf(FILE *input, json_error_t *error)
649 {
650     lex_t lex;
651     json_t *result;
652
653     if(lex_init(&lex, (get_func)fgetc, (eof_func)feof, input))
654         return NULL;
655
656     result = parse_json(&lex, error);
657
658     lex_close(&lex);
659     return result;
660 }