Fix null ptr reference for freeReplyObject YAZ-773
[yaz-moved-to-github.git] / src / json.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file json.c
7  * \brief JSON encoding/decoding
8  */
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <yaz/json.h>
14
15 #include <stdlib.h>
16 #include <errno.h>
17 #include <string.h>
18 #include <assert.h>
19 #include <stdio.h>
20
21 #include <yaz/xmalloc.h>
22
23 struct json_subst_info {
24     int idx;
25     struct json_subst_info *next;
26     struct json_node *node;
27 };
28
29 struct json_parser_s {
30     const char *buf;
31     const char *cp;
32     const char *err_msg;
33     struct json_subst_info *subst;
34 };
35
36 json_parser_t json_parser_create(void)
37 {
38     json_parser_t p = (json_parser_t) xmalloc(sizeof(*p));
39
40     p->buf = 0;
41     p->cp = 0;
42     p->err_msg = 0;
43     p->subst = 0;
44     return p;
45 }
46
47 void json_parser_subst(json_parser_t p, int idx, struct json_node *n)
48 {
49     struct json_subst_info **sb = &p->subst;
50     for (; *sb; sb = &(*sb)->next)
51         if ((*sb)->idx == idx)
52         {
53             (*sb)->node = n;
54             return;
55         }
56     *sb = xmalloc(sizeof(**sb));
57     (*sb)->next = 0;
58     (*sb)->node = n;
59     (*sb)->idx = idx;
60 }
61
62 void json_parser_destroy(json_parser_t p)
63 {
64     struct json_subst_info *sb = p->subst;
65     while (sb)
66     {
67         struct json_subst_info *sb_next = sb->next;
68         xfree(sb);
69         sb = sb_next;
70     }
71     xfree(p);
72 }
73
74 static int look_ch(json_parser_t p)
75 {
76     while (*p->cp && strchr(" \t\r\n\f", *p->cp))
77         (p->cp)++;
78     return *p->cp;
79 }
80
81 static void move_ch(json_parser_t p)
82 {
83     if (*p->cp)
84         (p->cp)++;
85 }
86
87 static struct json_node *json_new_node(json_parser_t p, enum json_node_type type)
88 {
89     struct json_node *n = (struct json_node *) xmalloc(sizeof(*n));
90     n->type = type;
91     n->u.link[0] = n->u.link[1] = 0;
92     return n;
93 }
94
95 void json_remove_node(struct json_node *n)
96 {
97     if (!n)
98         return;
99     switch (n->type)
100     {
101     case json_node_object:
102     case json_node_array:
103     case json_node_list:
104     case json_node_pair:
105         json_remove_node(n->u.link[0]);
106         json_remove_node(n->u.link[1]);
107         break;
108     case json_node_string:
109         xfree(n->u.string);
110         break;
111     case json_node_number:
112     case json_node_true:
113     case json_node_false:
114     case json_node_null:
115         break;
116     }
117     xfree(n);
118 }
119
120 static struct json_node *json_parse_object(json_parser_t p);
121 static struct json_node *json_parse_array(json_parser_t p);
122
123 static int json_one_char(const char **p, char *out)
124 {
125     if (**p == '\\' && p[0][1])
126     {
127         (*p)++;
128         switch(**p)
129         {
130         case '"':
131             *out = '"'; break;
132         case '\\':
133             *out = '\\'; break;
134         case '/':
135             *out = '/'; break;
136         case 'b':
137             *out = '\b'; break;
138         case 'f':
139             *out = '\f'; break;
140         case 'n':
141             *out = '\n'; break;
142         case 'r':
143             *out = '\r'; break;
144         case 't':
145             *out = '\t'; break;
146         case 'u':
147             if (p[0][1])
148             {
149                 unsigned code;
150                 char *outp = out;
151                 int error;
152                 size_t outbytesleft = 6;
153                 sscanf(*p + 1, "%4x", &code);
154                 if (!yaz_write_UTF8_char(code, &outp, &outbytesleft, &error))
155                 {
156                     *p += 5;
157                     return outp - out;
158                 }
159             }
160         default:
161             *out = '_'; break;
162             break;
163         }
164         (*p)++;
165         return 1;
166     }
167     else
168     {
169         *out = **p;
170         (*p)++;
171         return 1;
172     }
173 }
174
175 static struct json_node *json_parse_string(json_parser_t p)
176 {
177     struct json_node *n;
178     const char *cp;
179     char *dst;
180     int l = 0;
181     if (look_ch(p) != '\"')
182     {
183         p->err_msg = "string expected";
184         return 0;
185     }
186     move_ch(p);
187
188     cp = p->cp;
189     while (*cp && *cp != '"')
190     {
191         char out[6];
192         l += json_one_char(&cp, out);
193     }
194     if (!*cp)
195     {
196         p->err_msg = "missing \"";
197         return 0;
198     }
199     n = json_new_node(p, json_node_string);
200     dst = n->u.string = (char *) xmalloc(l + 1);
201
202     cp = p->cp;
203     while (*cp && *cp != '"')
204     {
205         char out[6];
206
207         l = json_one_char(&cp, out);
208         memcpy(dst, out, l);
209         dst += l;
210     }
211     *dst = '\0';
212     p->cp = cp+1;
213     return n;
214 }
215
216 static struct json_node *json_parse_number(json_parser_t p)
217 {
218     struct json_node *n;
219     char *endptr;
220     double v;
221
222     look_ch(p); // skip spaces
223     v = strtod(p->cp, &endptr);
224
225     if (endptr == p->cp)
226     {
227         p->err_msg = "bad number";
228         return 0;
229     }
230     p->cp = endptr;
231     n = json_new_node(p, json_node_number);
232     n->u.number = v;
233     return n;
234 }
235
236 static struct json_node *json_parse_value(json_parser_t p)
237 {
238     int c = look_ch(p);
239     if (c == '\"')
240         return json_parse_string(p);
241     else if (strchr("0123456789-+", c))
242         return json_parse_number(p);
243     else if (c == '{')
244         return json_parse_object(p);
245     else if (c == '[')
246         return json_parse_array(p);
247     else if (c == '%')
248     {
249         struct json_subst_info *sb;
250         int idx = 0;
251         p->cp++;
252         c = *p->cp;
253         while (c >= '0' && c <= '9')
254         {
255             idx = idx*10 + (c - '0');
256             p->cp++;
257             c = *p->cp;
258         }
259         for (sb = p->subst; sb; sb = sb->next)
260             if (sb->idx == idx)
261                 return sb->node;
262     }
263     else
264     {
265         char tok[8];
266         int i = 0;
267         while (c >= 'a' && c <= 'z' && i < 7)
268         {
269             tok[i++] = c;
270             p->cp++;
271             c = *p->cp;
272         }
273         tok[i] = 0;
274         if (!strcmp(tok, "true"))
275             return json_new_node(p, json_node_true);
276         else if (!strcmp(tok, "false"))
277             return json_new_node(p, json_node_false);
278         else if (!strcmp(tok, "null"))
279             return json_new_node(p, json_node_null);
280     }
281     p->err_msg = "bad token";
282     return 0;
283 }
284
285 static struct json_node *json_parse_elements(json_parser_t p)
286 {
287     struct json_node *n1 = json_parse_value(p);
288     struct json_node *m0, *m1;
289     if (!n1)
290         return 0;
291     m0 = m1 = json_new_node(p, json_node_list);
292     m1->u.link[0] = n1;
293     while (look_ch(p) == ',')
294     {
295         struct json_node *n2, *m2;
296         move_ch(p);
297         n2 = json_parse_value(p);
298         if (!n2)
299         {
300             json_remove_node(m0);
301             return 0;
302         }
303         m2 = json_new_node(p, json_node_list);
304         m2->u.link[0] = n2;
305
306         m1->u.link[1] = m2;
307         m1 = m2;
308     }
309     return m0;
310 }
311
312 static struct json_node *json_parse_array(json_parser_t p)
313 {
314     struct json_node *n;
315     if (look_ch(p) != '[')
316     {
317         p->err_msg = "expecting [";
318         return 0;
319     }
320     move_ch(p);
321     n = json_new_node(p, json_node_array);
322     if (look_ch(p) != ']')
323         n->u.link[0] = json_parse_elements(p);
324
325     if (look_ch(p) != ']')
326     {
327         p->err_msg = "expecting ]";
328         json_remove_node(n);
329         return 0;
330     }
331     move_ch(p);
332     return n;
333 }
334
335 static struct json_node *json_parse_pair(json_parser_t p)
336 {
337     struct json_node *s = json_parse_string(p);
338     struct json_node *v, *n;
339     if (!s)
340         return 0;
341     if (look_ch(p) != ':')
342     {
343         p->err_msg = "missing :";
344         json_remove_node(s);
345         return 0;
346     }
347     move_ch(p);
348     v = json_parse_value(p);
349     if (!v)
350     {
351         json_remove_node(s);
352         return 0;
353     }
354     n = json_new_node(p, json_node_pair);
355     n->u.link[0] = s;
356     n->u.link[1] = v;
357     return n;
358 }
359
360 static struct json_node *json_parse_members(json_parser_t p)
361 {
362     struct json_node *n1 = json_parse_pair(p);
363     struct json_node *m0, *m1;
364     if (!n1)
365         return 0;
366     m0 = m1 = json_new_node(p, json_node_list);
367     m1->u.link[0] = n1;
368     while (look_ch(p) == ',')
369     {
370         struct json_node *n2, *m2;
371         move_ch(p);
372         n2 = json_parse_pair(p);
373         if (!n2)
374         {
375             json_remove_node(m0);
376             return 0;
377         }
378         m2 = json_new_node(p, json_node_list);
379         m2->u.link[0] = n2;
380
381         m1->u.link[1] = m2;
382         m1 = m2;
383     }
384     return m0;
385 }
386
387 static struct json_node *json_parse_object(json_parser_t p)
388 {
389     struct json_node *n;
390     if (look_ch(p) != '{')
391     {
392         p->err_msg = "{ expected";
393         return 0;
394     }
395     move_ch(p);
396
397     n = json_new_node(p, json_node_object);
398     if (look_ch(p) != '}')
399     {
400         struct json_node *m = json_parse_members(p);
401         if (!m)
402         {
403             json_remove_node(n);
404             return 0;
405         }
406         n->u.link[0] = m;
407     }
408     if (look_ch(p) != '}')
409     {
410         p->err_msg = "Missing }";
411         json_remove_node(n);
412         return 0;
413     }
414     move_ch(p);
415     return n;
416 }
417
418 struct json_node *json_parser_parse(json_parser_t p, const char *json_str)
419 {
420     int c;
421     struct json_node *n;
422     p->buf = json_str;
423     p->cp = p->buf;
424
425     n = json_parse_value(p);
426     if (!n)
427         return 0;
428     c = look_ch(p);
429     if (c != 0)
430     {
431         p->err_msg = "extra characters";
432         json_remove_node(n);
433         return 0;
434     }
435     return n;
436 }
437
438 struct json_node *json_parse2(const char *json_str, const char **errmsg,
439                               size_t *pos)
440 {
441     json_parser_t p = json_parser_create();
442     struct json_node *n = 0;
443     if (!p)
444     {
445         if (errmsg)
446             *errmsg = "could not create parser";
447     }
448     else
449     {
450         n = json_parser_parse(p, json_str);
451         if (!n && errmsg)
452             *errmsg = json_parser_get_errmsg(p);
453         if (pos)
454             *pos = json_parser_get_position(p);
455         json_parser_destroy(p);
456     }
457     return n;
458 }
459
460 struct json_node *json_parse(const char *json_str, const char **errmsg)
461 {
462     return json_parse2(json_str, errmsg, 0);
463 }
464
465 static void json_indent(WRBUF result, int indent)
466 {
467     size_t l = wrbuf_len(result);
468     if (l == 0 || wrbuf_buf(result)[l-1] == '\n')
469     {
470         int i;
471         for (i = 0; i < indent; i++)
472             wrbuf_putc(result, ' ');
473     }
474 }
475
476 static void json_write_wrbuf_r(struct json_node *node, WRBUF result, int indent)
477 {
478     int sub_indent = -1;
479     if (indent >= 0)
480         sub_indent = indent + 1;
481     switch (node->type)
482     {
483     case json_node_object:
484         json_indent(result, indent);
485         wrbuf_puts(result, "{");
486         if (indent >= 0)
487         {
488             wrbuf_puts(result, "\n");
489             json_indent(result, sub_indent);
490         }
491         if (node->u.link[0])
492             json_write_wrbuf_r(node->u.link[0], result, sub_indent);
493         if (indent >= 0)
494         {
495             wrbuf_puts(result, "\n");
496             json_indent(result, indent);
497         }
498         wrbuf_puts(result, "}");
499         break;
500     case json_node_array:
501         json_indent(result, indent);
502         wrbuf_puts(result, "[");
503         if (indent >= 0)
504         {
505             wrbuf_puts(result, "\n");
506             json_indent(result, sub_indent);
507         }
508         if (node->u.link[0])
509         {
510             json_write_wrbuf_r(node->u.link[0], result, sub_indent);
511         }
512         if (indent >= 0)
513         {
514             wrbuf_puts(result, "\n");
515             json_indent(result, indent);
516         }
517         wrbuf_puts(result, "]");
518         break;
519     case json_node_list:
520         json_write_wrbuf_r(node->u.link[0], result, indent);
521         if (node->u.link[1])
522         {
523             wrbuf_puts(result, ",");
524             if (indent >= 0)
525                 wrbuf_puts(result, " ");
526             json_write_wrbuf_r(node->u.link[1], result, indent);
527         }
528         break;
529     case json_node_pair:
530         json_write_wrbuf_r(node->u.link[0], result, indent);
531         wrbuf_puts(result, ":");
532         if (indent >= 0)
533             wrbuf_puts(result, " ");
534         json_write_wrbuf_r(node->u.link[1], result, indent);
535         break;
536     case json_node_string:
537         wrbuf_puts(result, "\"");
538         wrbuf_json_puts(result, node->u.string);
539         wrbuf_puts(result, "\"");
540         break;
541     case json_node_number:
542         wrbuf_printf(result, "%lg", node->u.number);
543         break;
544     case json_node_true:
545         wrbuf_puts(result, "true");
546         break;
547     case json_node_false:
548         wrbuf_puts(result, "false");
549         break;
550     case json_node_null:
551         wrbuf_puts(result, "null");
552         break;
553     }
554 }
555
556 void json_write_wrbuf_pretty(struct json_node *node, WRBUF result)
557 {
558     json_write_wrbuf_r(node, result, 1);
559 }
560
561 void json_write_wrbuf(struct json_node *node, WRBUF result)
562 {
563     json_write_wrbuf_r(node, result, -1);
564 }
565
566 static struct json_node **json_get_objectp(struct json_node *n,
567                                            const char *name)
568 {
569     if (n && n->type == json_node_object)
570     {
571         for (n = n->u.link[0]; n; n = n->u.link[1])
572         {
573             struct json_node *c = n->u.link[0];
574             if (c && c->type == json_node_pair &&
575                 c->u.link[0] && c->u.link[0]->type == json_node_string)
576                 if (!strcmp(name, c->u.link[0]->u.string))
577                     return &c->u.link[1];
578         }
579     }
580     return 0;
581 }
582
583 struct json_node *json_get_object(struct json_node *n, const char *name)
584 {
585     struct json_node **np = json_get_objectp(n, name);
586
587     if (np)
588         return *np;
589     return 0;
590 }
591
592 struct json_node *json_detach_object(struct json_node *n, const char *name)
593 {
594     struct json_node **np = json_get_objectp(n, name);
595
596     if (np)
597     {
598         struct json_node *n = *np;
599         *np = 0;
600         return n;
601     }
602     return 0;
603 }
604
605 struct json_node *json_get_elem(struct json_node *n, int idx)
606 {
607     if (n && n->type == json_node_array)
608     {
609         for (n = n->u.link[0]; n; n = n->u.link[1])
610         {
611             if (--idx < 0)
612                 return n->u.link[0];
613         }
614     }
615     return 0;
616 }
617
618 int json_count_children(struct json_node *n)
619 {
620     int i = 0;
621
622     if (n && (n->type == json_node_array || n->type == json_node_object))
623     {
624         for (n = n->u.link[0]; n; n = n->u.link[1])
625             i++;
626     }
627     return i;
628 }
629
630 int json_append_array(struct json_node *dst, struct json_node *src)
631 {
632     if (dst && src &&
633         dst->type == json_node_array && src->type == json_node_array)
634     {
635         struct json_node **np = &dst->u.link[0];
636         while (*np)
637             np = &(*np)->u.link[1];
638         *np = src->u.link[0];
639         src->u.link[0] = 0;
640         json_remove_node(src);
641         return 0;
642     }
643     return -1;
644 }
645
646 const char *json_parser_get_errmsg(json_parser_t p)
647 {
648     return p->err_msg;
649 }
650
651 size_t json_parser_get_position(json_parser_t p)
652 {
653     return p->cp - p->buf;
654 }
655
656 /*
657  * Local variables:
658  * c-basic-offset: 4
659  * c-file-style: "Stroustrup"
660  * indent-tabs-mode: nil
661  * End:
662  * vim: shiftwidth=4 tabstop=8 expandtab
663  */