YAZ  4.2.57
json.c
Go to the documentation of this file.
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2013 Index Data
3  * See the file LICENSE for details.
4  */
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 
24  int idx;
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;
34 };
35 
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 
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 
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 
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 
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  }
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 
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;
232  n->u.number = v;
233  return n;
234 }
235 
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 
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 
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);
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 
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  }
355  n->u.link[0] = s;
356  n->u.link[1] = v;
357  return n;
358 }
359 
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 
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 
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 {
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);
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 wrbuf_json_write(WRBUF b, const char *cp, size_t sz)
466 {
467  size_t i;
468  for (i = 0; i < sz; i++)
469  {
470  if (cp[i] > 0 && cp[i] < 32)
471  {
472  wrbuf_putc(b, '\\');
473  switch (cp[i])
474  {
475  case '\b': wrbuf_putc(b, 'b'); break;
476  case '\f': wrbuf_putc(b, 'f'); break;
477  case '\n': wrbuf_putc(b, 'n'); break;
478  case '\r': wrbuf_putc(b, 'r'); break;
479  case '\t': wrbuf_putc(b, 't'); break;
480  default:
481  wrbuf_printf(b, "u%04x", cp[i]);
482  }
483  }
484  else if (cp[i] == '"')
485  {
486  wrbuf_putc(b, '\\'); wrbuf_putc(b, '"');
487  }
488  else if (cp[i] == '\\')
489  {
490  wrbuf_putc(b, '\\'); wrbuf_putc(b, '\\');
491  }
492  else
493  { /* leave encoding as raw UTF-8 */
494  wrbuf_putc(b, cp[i]);
495  }
496  }
497 
498 }
499 
500 void wrbuf_json_puts(WRBUF b, const char *str)
501 {
502  wrbuf_json_write(b, str, strlen(str));
503 }
504 
505 static void json_indent(WRBUF result, int indent)
506 {
507  size_t l = wrbuf_len(result);
508  if (l == 0 || wrbuf_buf(result)[l-1] == '\n')
509  {
510  int i;
511  for (i = 0; i < indent; i++)
512  wrbuf_putc(result, ' ');
513  }
514 }
515 
516 static void json_write_wrbuf_r(struct json_node *node, WRBUF result, int indent)
517 {
518  int sub_indent = -1;
519  if (indent >= 0)
520  sub_indent = indent + 1;
521  switch (node->type)
522  {
523  case json_node_object:
524  json_indent(result, indent);
525  wrbuf_puts(result, "{");
526  if (indent >= 0)
527  {
528  wrbuf_puts(result, "\n");
529  json_indent(result, sub_indent);
530  }
531  if (node->u.link[0])
532  json_write_wrbuf_r(node->u.link[0], result, sub_indent);
533  if (indent >= 0)
534  {
535  wrbuf_puts(result, "\n");
536  json_indent(result, indent);
537  }
538  wrbuf_puts(result, "}");
539  break;
540  case json_node_array:
541  json_indent(result, indent);
542  wrbuf_puts(result, "[");
543  if (indent >= 0)
544  {
545  wrbuf_puts(result, "\n");
546  json_indent(result, sub_indent);
547  }
548  if (node->u.link[0])
549  {
550  json_write_wrbuf_r(node->u.link[0], result, sub_indent);
551  }
552  if (indent >= 0)
553  {
554  wrbuf_puts(result, "\n");
555  json_indent(result, indent);
556  }
557  wrbuf_puts(result, "]");
558  break;
559  case json_node_list:
560  json_write_wrbuf_r(node->u.link[0], result, indent);
561  if (node->u.link[1])
562  {
563  wrbuf_puts(result, ",");
564  if (indent >= 0)
565  wrbuf_puts(result, " ");
566  json_write_wrbuf_r(node->u.link[1], result, indent);
567  }
568  break;
569  case json_node_pair:
570  json_write_wrbuf_r(node->u.link[0], result, indent);
571  wrbuf_puts(result, ":");
572  if (indent >= 0)
573  wrbuf_puts(result, " ");
574  json_write_wrbuf_r(node->u.link[1], result, indent);
575  break;
576  case json_node_string:
577  wrbuf_puts(result, "\"");
578  wrbuf_json_puts(result, node->u.string);
579  wrbuf_puts(result, "\"");
580  break;
581  case json_node_number:
582  wrbuf_printf(result, "%lg", node->u.number);
583  break;
584  case json_node_true:
585  wrbuf_puts(result, "true");
586  break;
587  case json_node_false:
588  wrbuf_puts(result, "false");
589  break;
590  case json_node_null:
591  wrbuf_puts(result, "null");
592  break;
593  }
594 }
595 
597 {
598  json_write_wrbuf_r(node, result, 1);
599 }
600 
601 void json_write_wrbuf(struct json_node *node, WRBUF result)
602 {
603  json_write_wrbuf_r(node, result, -1);
604 }
605 
606 static struct json_node **json_get_objectp(struct json_node *n,
607  const char *name)
608 {
609  if (n && n->type == json_node_object)
610  {
611  for (n = n->u.link[0]; n; n = n->u.link[1])
612  {
613  struct json_node *c = n->u.link[0];
614  if (c && c->type == json_node_pair &&
615  c->u.link[0] && c->u.link[0]->type == json_node_string)
616  if (!strcmp(name, c->u.link[0]->u.string))
617  return &c->u.link[1];
618  }
619  }
620  return 0;
621 }
622 
623 struct json_node *json_get_object(struct json_node *n, const char *name)
624 {
625  struct json_node **np = json_get_objectp(n, name);
626 
627  if (np)
628  return *np;
629  return 0;
630 }
631 
632 struct json_node *json_detach_object(struct json_node *n, const char *name)
633 {
634  struct json_node **np = json_get_objectp(n, name);
635 
636  if (np)
637  {
638  struct json_node *n = *np;
639  *np = 0;
640  return n;
641  }
642  return 0;
643 }
644 
645 struct json_node *json_get_elem(struct json_node *n, int idx)
646 {
647  if (n && n->type == json_node_array)
648  {
649  for (n = n->u.link[0]; n; n = n->u.link[1])
650  {
651  if (--idx < 0)
652  return n->u.link[0];
653  }
654  }
655  return 0;
656 }
657 
659 {
660  int i = 0;
661 
662  if (n && (n->type == json_node_array || n->type == json_node_object))
663  {
664  for (n = n->u.link[0]; n; n = n->u.link[1])
665  i++;
666  }
667  return i;
668 }
669 
670 int json_append_array(struct json_node *dst, struct json_node *src)
671 {
672  if (dst && src &&
673  dst->type == json_node_array && src->type == json_node_array)
674  {
675  struct json_node **np = &dst->u.link[0];
676  while (*np)
677  np = &(*np)->u.link[1];
678  *np = src->u.link[0];
679  src->u.link[0] = 0;
680  json_remove_node(src);
681  return 0;
682  }
683  return -1;
684 }
685 
687 {
688  return p->err_msg;
689 }
690 
692 {
693  return p->cp - p->buf;
694 }
695 
696 /*
697  * Local variables:
698  * c-basic-offset: 4
699  * c-file-style: "Stroustrup"
700  * indent-tabs-mode: nil
701  * End:
702  * vim: shiftwidth=4 tabstop=8 expandtab
703  */