added scr_lvled, a bunch of libraries, and improved framework code
[raydungeon] / libs / goat3d / src / json.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include "dynarr.h"
6
7 #if defined(_WIN32) || defined(__WATCOMC__)
8 #include <malloc.h>
9 #else
10 #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
11 #include <alloca.h>
12 #endif
13 #endif
14
15 #include "json.h"
16
17 #ifdef _MSC_VER
18 #define strncasecmp strnicmp
19 #endif
20
21 struct json_obj *json_alloc_obj(void)
22 {
23         struct json_obj *obj;
24
25         if(!(obj = malloc(sizeof *obj))) {
26                 fprintf(stderr, "json_alloc_obj: failed to allocate object\n");
27                 return 0;
28         }
29         json_init_obj(obj);
30         return obj;
31 }
32
33 void json_free_obj(struct json_obj *obj)
34 {
35         json_destroy_obj(obj);
36         free(obj);
37 }
38
39 void json_init_obj(struct json_obj *obj)
40 {
41         memset(obj, 0, sizeof *obj);
42 }
43
44 void json_destroy_obj(struct json_obj *obj)
45 {
46         int i;
47
48         for(i=0; i<obj->num_items; i++) {
49                 json_destroy_item(obj->items + i);
50         }
51         free(obj->items);
52 }
53
54 struct json_arr *json_alloc_arr(void)
55 {
56         struct json_arr *arr;
57
58         if(!(arr = malloc(sizeof *arr))) {
59                 fprintf(stderr, "json_alloc_arr: failed to allocate array\n");
60                 return 0;
61         }
62         json_init_arr(arr);
63         return arr;
64 }
65
66 void json_free_arr(struct json_arr *arr)
67 {
68         json_destroy_arr(arr);
69         free(arr);
70 }
71
72 void json_init_arr(struct json_arr *arr)
73 {
74         memset(arr, 0, sizeof *arr);
75 }
76
77 void json_destroy_arr(struct json_arr *arr)
78 {
79         int i;
80
81         for(i=0; i<arr->size; i++) {
82                 json_destroy_value(arr->val + i);
83         }
84         free(arr->val);
85 }
86
87
88 int json_item(struct json_item *item, const char *name)
89 {
90         memset(item, 0, sizeof *item);
91
92         if(!(item->name = strdup(name))) {
93                 fprintf(stderr, "json_item: failed to allocate name\n");
94                 return -1;
95         }
96         return 0;
97 }
98
99 void json_destroy_item(struct json_item *item)
100 {
101         free(item->name);
102         json_destroy_value(&item->val);
103 }
104
105 int json_value_str(struct json_value *jv, const char *str)
106 {
107         jv->type = JSON_STR;
108
109         jv->str = 0;
110         if(str && !(jv->str = strdup(str))) {
111                 fprintf(stderr, "json_value_str: failed to duplicate string\n");
112                 return -1;
113         }
114         return 0;
115 }
116
117 void json_value_num(struct json_value *jv, double num)
118 {
119         jv->type = JSON_NUM;
120         jv->num = num;
121 }
122
123 void json_value_bool(struct json_value *jv, int bval)
124 {
125         jv->type = JSON_BOOL;
126         jv->boolean = bval;
127 }
128
129 void json_value_obj(struct json_value *jv, struct json_obj *obj)
130 {
131         jv->type = JSON_OBJ;
132         if(obj) {
133                 jv->obj = *obj;
134         } else {
135                 json_init_obj(&jv->obj);
136         }
137 }
138
139 void json_value_arr(struct json_value *jv, struct json_arr *arr)
140 {
141         jv->type = JSON_ARR;
142         if(arr) {
143                 jv->arr = *arr;
144         } else {
145                 json_init_arr(&jv->arr);
146         }
147 }
148
149 void json_destroy_value(struct json_value *jv)
150 {
151         switch(jv->type) {
152         case JSON_STR:
153                 free(jv->str);
154                 break;
155
156         case JSON_OBJ:
157                 json_destroy_obj(&jv->obj);
158                 break;
159
160         case JSON_ARR:
161                 json_destroy_arr(&jv->arr);
162                 break;
163
164         default:
165                 break;
166         }
167 }
168
169 int json_obj_append(struct json_obj *obj, const struct json_item *item)
170 {
171         if(obj->num_items >= obj->max_items) {
172                 int newsz = obj->max_items ? (obj->max_items << 1) : 8;
173                 void *tmp = realloc(obj->items, newsz * sizeof *obj->items);
174                 if(!tmp) {
175                         fprintf(stderr, "json_obj_append: failed to grow items array (%d)\n", newsz);
176                         return -1;
177                 }
178                 obj->items = tmp;
179                 obj->max_items = newsz;
180         }
181
182         obj->items[obj->num_items++] = *item;
183         return 0;
184 }
185
186 int json_arr_append(struct json_arr *arr, const struct json_value *val)
187 {
188         if(arr->size >= arr->maxsize) {
189                 int newsz = arr->maxsize ? (arr->maxsize << 1) : 8;
190                 void *tmp = realloc(arr->val, newsz * sizeof *arr->val);
191                 if(!tmp) {
192                         fprintf(stderr, "json_arr_append: failed to grow array (%d)\n", newsz);
193                         return -1;
194                 }
195                 arr->val = tmp;
196                 arr->maxsize = newsz;
197         }
198
199         arr->val[arr->size++] = *val;
200         return 0;
201 }
202
203 struct json_item *json_find_item(const struct json_obj *obj, const char *name)
204 {
205         int i;
206         for(i=0; i<obj->num_items; i++) {
207                 if(strcmp(obj->items[i].name, name) == 0) {
208                         return obj->items + i;
209                 }
210         }
211         return 0;
212 }
213
214 /* lookup functions */
215
216 struct json_value *json_lookup(struct json_obj *obj, const char *path)
217 {
218         int len;
219         char *pelem;
220         const char *endp;
221         struct json_item *it = 0;
222
223         pelem = alloca(strlen(path) + 1);
224         while(*path) {
225                 endp = path;
226                 while(*endp && *endp != '.') endp++;
227                 if(!(len = endp - path)) break;
228
229                 memcpy(pelem, path, len);
230                 pelem[len] = 0;
231
232                 /* continue after the . or point at the terminator */
233                 path = endp;
234                 if(*path == '.') path++;
235
236                 if(!(it = json_find_item(obj, pelem))) {
237                         return 0;
238                 }
239
240                 if(it->val.type != JSON_OBJ) {
241                         /* we hit a leaf. If the path continues we failed */
242                         if(*path) return 0;
243                 }
244
245                 /* item is an object, we can continue the lookup if necessary */
246                 obj = &it->val.obj;
247         }
248
249         return it ? &it->val : 0;
250 }
251
252 const char *json_lookup_str(struct json_obj *obj, const char *path, const char *def)
253 {
254         struct json_value *val;
255
256         if(!(val = json_lookup(obj, path)) || val->type != JSON_STR) {
257                 return def;
258         }
259         return val->str;
260 }
261
262 double json_lookup_num(struct json_obj *obj, const char *path, double def)
263 {
264         struct json_value *val;
265
266         if(!(val = json_lookup(obj, path)) || val->type != JSON_NUM) {
267                 return def;
268         }
269         return val->num;
270 }
271
272 int json_lookup_bool(struct json_obj *obj, const char *path, int def)
273 {
274         struct json_value *val;
275
276         if(!(val = json_lookup(obj, path)) || val->type != JSON_BOOL) {
277                 return def;
278         }
279         return val->boolean;
280 }
281
282 struct json_obj *json_lookup_obj(struct json_obj *obj, const char *path, struct json_obj *def)
283 {
284         struct json_value *val;
285
286         if(!(val = json_lookup(obj, path)) || val->type != JSON_OBJ) {
287                 return def;
288         }
289         return &val->obj;
290 }
291
292 struct json_arr *json_lookup_arr(struct json_obj *obj, const char *path, struct json_arr *def)
293 {
294         struct json_value *val;
295
296         if(!(val = json_lookup(obj, path)) || val->type != JSON_ARR) {
297                 return def;
298         }
299         return &val->arr;
300 }
301
302
303 /* ---- parser ---- */
304
305 #define MAX_TOKEN_SIZE  512
306 struct parser {
307         char *text;
308         int nextc;
309         char *token;
310 };
311
312 enum { TOKEN_NUM, TOKEN_STR, TOKEN_BOOL };      /* plus all the single-char tokens */
313
314
315 static int item(struct parser *p, struct json_item *it);
316 static int array(struct parser *p, struct json_arr *arr);
317 static int object(struct parser *p, struct json_obj *obj);
318
319
320 static int next_char(struct parser *p)
321 {
322         while(*p->text) {
323                 p->nextc = *p->text++;
324                 if(!isspace(p->nextc)) break;
325         }
326         return p->nextc;
327 }
328
329 #define SET_TOKEN(token, str, len) \
330         do { \
331                 DYNARR_RESIZE(token, (len) + 1); \
332                 memcpy(token, str, len); \
333                 token[len] = 0; \
334         } while(0)
335
336 static int next_token(struct parser *p)
337 {
338         int len;
339         char *ptr, *s;
340
341         if(!p->nextc) return -1;
342
343         switch(p->nextc) {
344         case '{':
345         case '}':
346         case ',':
347         case '[':
348         case ']':
349         case ':':
350                 SET_TOKEN(p->token, &p->nextc, 1);
351                 next_char(p);
352                 return p->token[0];
353
354         case '"':
355                 DYNARR_CLEAR(p->token);
356                 next_char(p);
357                 while(p->nextc && p->nextc != '"') {
358                         DYNARR_STRPUSH(p->token, p->nextc);
359                         next_char(p);
360                 }
361                 next_char(p);
362                 return TOKEN_STR;
363
364         default:
365                 break;
366         }
367
368         s = p->text - 1;
369
370         strtod(s, &ptr);
371         if(ptr != s) {
372                 len = ptr - s;
373                 SET_TOKEN(p->token, s, len);
374                 p->text = ptr;
375                 next_char(p);
376                 return TOKEN_NUM;
377         }
378
379         if(strncasecmp(s, "true", 4) == 0) {
380                 SET_TOKEN(p->token, "true", 4);
381                 p->text += 3;
382                 next_char(p);
383                 return TOKEN_BOOL;
384         }
385         if(strncasecmp(s, "false", 5) == 0) {
386                 SET_TOKEN(p->token, "false", 5);
387                 p->text += 4;
388                 next_char(p);
389                 return TOKEN_BOOL;
390         }
391
392         SET_TOKEN(p->token, &p->nextc, 1);
393         fprintf(stderr, "json_parse: unexpected character: %c\n", p->nextc);
394         return -1;
395 }
396
397 static int expect(struct parser *p, int tok)
398 {
399         return next_token(p) == tok ? 1 : 0;
400 }
401
402 static const char *toktypestr(int tok)
403 {
404         static char buf[] = "' '";
405         switch(tok) {
406         case TOKEN_NUM: return "number";
407         case TOKEN_STR: return "string";
408         case TOKEN_BOOL: return "boolean";
409         default:
410                 break;
411         }
412         buf[1] = tok;
413         return buf;
414 }
415
416 #define EXPECT(p, x) \
417         do { \
418                 if(!expect(p, x)) { \
419                         fprintf(stderr, "json_parse: expected: %s, found: %s\n", toktypestr(x), (p)->token); \
420                         return -1; \
421                 } \
422         } while(0)
423
424 static int value(struct parser *p, struct json_value *val)
425 {
426         int toktype;
427         struct json_obj obj;
428         struct json_arr arr;
429
430         toktype = next_token(p);
431         switch(toktype) {
432         case TOKEN_STR:
433                 if(json_value_str(val, p->token) == -1) {
434                         return -1;
435                 }
436                 break;
437
438         case TOKEN_NUM:
439                 json_value_num(val, atof(p->token));
440                 break;
441
442         case TOKEN_BOOL:
443                 json_value_bool(val, *p->token == 't' ? 1 : 0);
444                 break;
445
446         case '{':       /* object */
447                 if(object(p, &obj) == -1) {
448                         return -1;
449                 }
450                 json_value_obj(val, &obj);
451                 break;
452
453         case '[':       /* array */
454                 if(array(p, &arr) == -1) {
455                         return -1;
456                 }
457                 json_value_arr(val, &arr);
458                 break;
459
460         default:
461                 fprintf(stderr, "json_parse: unexpected token %s while parsing item\n", p->text);
462                 return -1;
463         }
464         return 0;
465 }
466
467 static int item(struct parser *p, struct json_item *it)
468 {
469         EXPECT(p, TOKEN_STR);
470         if(json_item(it, p->token) == -1) {
471                 return -1;
472         }
473         EXPECT(p, ':');
474         if(value(p, &it->val) == -1) {
475                 free(it->name);
476                 return -1;
477         }
478         return 0;
479 }
480
481 static int array(struct parser *p, struct json_arr *arr)
482 {
483         struct json_value val;
484
485         json_init_arr(arr);
486
487         while(p->nextc != -1 && p->nextc != ']') {
488                 if(value(p, &val) == -1) {
489                         fprintf(stderr, "json_parse: expected value in array\n");
490                         json_destroy_arr(arr);
491                         return -1;
492                 }
493
494                 if(json_arr_append(arr, &val) == -1) {
495                         json_destroy_value(&val);
496                         json_destroy_arr(arr);
497                         return -1;
498                 }
499
500                 if(p->nextc == ',') expect(p, ',');     /* eat up comma separator */
501         }
502         EXPECT(p, ']');
503         return 0;
504 }
505
506 static int object(struct parser *p, struct json_obj *obj)
507 {
508         struct json_item it;
509
510         json_init_obj(obj);
511
512         while(p->nextc != -1 && p->nextc != '}') {
513                 if(item(p, &it) == -1) {
514                         fprintf(stderr, "json_parse: expected item in object\n");
515                         json_destroy_obj(obj);
516                         return -1;
517                 }
518
519                 if(json_obj_append(obj, &it) == -1) {
520                         json_destroy_item(&it);
521                         json_destroy_obj(obj);
522                         return -1;
523                 }
524
525                 if(p->nextc == ',') expect(p, ',');     /* eat up comma separator */
526         }
527         EXPECT(p, '}');
528         return 0;
529 }
530
531 int json_parse(struct json_obj *root, const char *text)
532 {
533         struct parser p;
534
535         if(!text || !*text) return -1;
536
537         p.nextc = *text;
538         p.text = (char*)(text + 1);
539         if(!(p.token = dynarr_alloc(0, 1))) {
540                 fprintf(stderr, "json_parse: failed to allocate token dynamic array\n");
541                 return -1;
542         }
543
544         EXPECT(&p, '{');
545         if(object(&p, root) == -1) {
546                 dynarr_free(p.token);
547                 return -1;
548         }
549         dynarr_free(p.token);
550         return 0;
551 }
552
553
554 static void putind(FILE *fp, int ind)
555 {
556         int i;
557         for(i=0; i<ind; i++) {
558                 fputs("  ", fp);
559         }
560 }
561
562 void json_print(FILE *fp, struct json_obj *root)
563 {
564         json_print_obj(fp, root, 0);
565         fputc('\n', fp);
566 }
567
568 void json_print_obj(FILE *fp, struct json_obj *obj, int ind)
569 {
570         int i;
571
572         fputs("{\n", fp);
573
574         for(i=0; i<obj->num_items; i++) {
575                 putind(fp, ind + 1);
576                 json_print_item(fp, obj->items + i, ind + 1);
577                 if(i < obj->num_items - 1) {
578                         fputs(",\n", fp);
579                 } else {
580                         fputc('\n', fp);
581                 }
582         }
583
584         putind(fp, ind);
585         fputs("}", fp);
586 }
587
588 void json_print_arr(FILE *fp, struct json_arr *arr, int ind)
589 {
590         int i;
591
592         fputs("[\n", fp);
593
594         for(i=0; i<arr->size; i++) {
595                 putind(fp, ind + 1);
596                 json_print_value(fp, arr->val + i, ind + 1);
597                 if(i < arr->size - 1) {
598                         fputs(",\n", fp);
599                 } else {
600                         fputc('\n', fp);
601                 }
602         }
603
604         putind(fp, ind);
605         fputs("]", fp);
606 }
607
608 void json_print_item(FILE *fp, struct json_item *item, int ind)
609 {
610         fprintf(fp, "\"%s\": ", item->name);
611         json_print_value(fp, &item->val, ind);
612 }
613
614 void json_print_value(FILE *fp, struct json_value *val, int ind)
615 {
616         switch(val->type) {
617         case JSON_STR:
618                 fprintf(fp, "\"%s\"", val->str);
619                 break;
620         case JSON_NUM:
621                 fprintf(fp, "%g", val->num);
622                 break;
623         case JSON_BOOL:
624                 fprintf(fp, "%s", val->boolean ? "true" : "false");
625                 break;
626         case JSON_OBJ:
627                 json_print_obj(fp, &val->obj, ind);
628                 break;
629         case JSON_ARR:
630                 json_print_arr(fp, &val->arr, ind);
631                 break;
632         default:
633                 fputs("<UNKNOWN>", fp);
634         }
635 }