1 /* -*- mode: C; mode: fold -*- */
2 /*
3 Copyright (C) 2013-2017,2018 John E. Davis, Manfred Hanke
4
5 This file is part of the S-Lang Library.
6
7 The S-Lang Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 The S-Lang Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this library; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 USA.
21 */
22
23 #define _BSD_SOURCE 1 /* to get strtoll */
24 #define _DEFAULT_SOURCE 1
25 #include "config.h"
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <slang.h>
31
32 SLANG_MODULE(json);
33
34 #define JSON_MODULE_VERSION_NUMBER 300
35 static char* json_module_version_string = "pre-0.3.0";
36
37 /*{{{ JSON grammar based upon json.org & ietf.org/rfc/rfc4627.txt
38 *
39 * object:
40 * { }
41 * { members }
42 * members:
43 * pair
44 * pair , members
45 * pair:
46 * string : value
47 *
48 * array:
49 * [ ]
50 * [ elements ]
51 * elements:
52 * value
53 * value , elements
54 *
55 * value:
56 * string
57 * number
58 * object
59 * array
60 * true
61 * false
62 * null
63 *
64 * Since a pair consists of a (arbitrary string) keyword and a value,
65 * a JSON object maps onto a structure (Struct_Type) in S-Lang.
66 *
67 * Since a JSON array is a heterogenous collection of elements,
68 * these map onto a list (List_Type) in S-Lang.
69 *
70 * Since S-Lang has no separate boolean type,
71 * true|false are represented as 1|0 of UChar_Type.
72 */
73
74 #define BEGIN_ARRAY '['
75 #define BEGIN_OBJECT '{'
76 #define END_ARRAY ']'
77 #define END_OBJECT '}'
78 #define VALUE_SEPARATOR ','
79 #define NAME_SEPARATOR ':'
80 #define STRING_DELIMITER '"'
81 #define ESCAPE_CHARACTER '\\'
82
83 /*}}}*/
84
85 static int Json_Parse_Error = -1;
86 static int Json_Invalid_Json_Error = -1;
87
88 #define DESCRIBE_CHAR_FMT "'%c' = 0x%02X"
89 #define DESCRIBE_CHAR(ch) ch, (unsigned int)(unsigned char)ch
90
91 static int Max_Recursion_Depth = 100;
92 typedef struct
93 {
94 char *ptr; /* points into input string */
95 int depth;
96 }
97 Parse_Type;
98
skip_white(Parse_Type * p)99 static void skip_white (Parse_Type *p) /*{{{*/
100 {
101 unsigned char *s = (unsigned char *)p->ptr;
102
103 while ((*s == ' ') || (*s == '\t') || (*s == '\n') || (*s == '\r'))
104 s++;
105
106 p->ptr = (char *)s;
107 }
108 /*}}}*/
109
looking_at(Parse_Type * p,char ch)110 static int looking_at (Parse_Type *p, char ch) /*{{{*/
111 {
112 return *p->ptr == ch;
113 }
114 /*}}}*/
115
skip_char(Parse_Type * p,char ch)116 static int skip_char (Parse_Type *p, char ch) /*{{{*/
117 {
118 if (! looking_at (p, ch))
119 return 0;
120
121 p->ptr++;
122 return 1;
123 }
124 /*}}}*/
125
parse_hex_digit(char ch)126 static int parse_hex_digit (char ch) /*{{{*/
127 {
128 if ('0' <= ch && ch <= '9') return ch - '0';
129 if ('A' <= ch && ch <= 'F') return 10 + ch - 'A';
130 if ('a' <= ch && ch <= 'f') return 10 + ch - 'a';
131 else return -1;
132 }
133 /*}}}*/
134
parse_4_hex_digits(char * s,unsigned int * new_string_len,char * new_string,int * is_binary_stringp)135 static char *parse_4_hex_digits (char *s, unsigned int *new_string_len, char *new_string, int *is_binary_stringp) /*{{{*/
136 {
137 int d1, d2, d3, d4;
138 SLwchar_Type wchar;
139 #define BUFLEN 6
140 SLuchar_Type buf[BUFLEN], *u;
141
142 if ( (-1 == (d1 = parse_hex_digit (s[0])))
143 || (-1 == (d2 = parse_hex_digit (s[1])))
144 || (-1 == (d3 = parse_hex_digit (s[2])))
145 || (-1 == (d4 = parse_hex_digit (s[3]))))
146 {
147 SLang_verror (Json_Parse_Error, "Illegal Unicode escape sequence in JSON string: \\u%c%c%c%c", s[0], s[1], s[2], s[3]); /* may contain '\000' */
148 return NULL;
149 }
150
151 wchar = (d1 << 12) + (d2 << 8) + (d3 << 4) + d4;
152 if (is_binary_stringp != NULL)
153 *is_binary_stringp = (wchar == 0);
154
155 u = new_string ? (SLuchar_Type*)new_string : buf;
156 *new_string_len += SLutf8_encode (wchar, u, BUFLEN) - u;
157 #undef BUFLEN
158
159 return s+4;
160 }
161 /*}}}*/
162
parse_string_length_and_move_ptr(Parse_Type * p,unsigned int * lenp,int * is_binary_stringp)163 static int parse_string_length_and_move_ptr (Parse_Type *p, unsigned int *lenp, int *is_binary_stringp) /*{{{*/
164 {
165 unsigned int new_string_len = 0;
166 char *s = p->ptr;
167
168 *lenp = 0; *is_binary_stringp = 0;
169
170 while (1)
171 {
172 char ch = *s++;
173
174 /* STRING_DELIMITER = 34, SPACE = 32 */
175 if ((unsigned char)ch <= STRING_DELIMITER)
176 {
177 if (ch == STRING_DELIMITER)
178 break;
179
180 if (ch == 0)
181 {
182 SLang_verror (Json_Parse_Error, "Unexpected end of input seen while parsing a JSON string");
183 return -1;
184 }
185 if (ch < 32)
186 {
187 SLang_verror (Json_Parse_Error, "Control character 0x%02X in JSON string must be escaped", (unsigned int)ch);
188 return -1;
189 }
190 /* drop */
191 }
192
193 if (ch == ESCAPE_CHARACTER)
194 {
195 ch = *s++;
196 switch (ch)
197 {
198 case STRING_DELIMITER:
199 case ESCAPE_CHARACTER:
200 case '/':
201 case 'b': case 'f': case 'n': case 'r': case 't':
202 new_string_len++;
203 break;
204 case 'u':
205 {
206 int isbin;
207 if (NULL == (s = parse_4_hex_digits (s, &new_string_len, NULL, &isbin)))
208 return -1;
209 *is_binary_stringp |= isbin;
210 break;
211 }
212 default:
213 SLang_verror (Json_Parse_Error, "Illegal escaped character " DESCRIBE_CHAR_FMT " in JSON string", DESCRIBE_CHAR(ch));
214 return -1;
215 }
216 }
217 else
218 new_string_len++;
219 }
220
221 p->ptr = s;
222 *lenp = new_string_len;
223 return 0;
224 }
225 /*}}}*/
226
227 /* try to use string_buffer
228 * if there is enough space and the string is not a binary string.
229 */
parse_string(Parse_Type * p,char * string_buffer,unsigned int buflen,unsigned int * bstring_lenp)230 static char *parse_string (Parse_Type *p,
231 char *string_buffer, unsigned int buflen,
232 unsigned int *bstring_lenp) /*{{{*/
233 {
234 char *s, *new_string;
235 unsigned int new_string_pos, new_string_len;
236 int is_binary_string = 0;
237
238 s = p->ptr;
239
240 if (-1 == parse_string_length_and_move_ptr (p, &new_string_len, &is_binary_string))
241 return NULL;
242
243 new_string = string_buffer;
244 if (((new_string_len >= buflen) || is_binary_string)
245 && (NULL == (new_string = SLmalloc (new_string_len + 1))))
246 return NULL;
247
248 new_string_pos = 0;
249
250 while (new_string_pos < new_string_len)
251 {
252 char ch = *s++;
253
254 if ((ch == STRING_DELIMITER) || ((unsigned char)ch < 32))
255 goto return_application_error;
256
257 if (ch != ESCAPE_CHARACTER)
258 {
259 new_string[new_string_pos++] = ch;
260 continue;
261 }
262
263 ch = *s++;
264 switch (ch)
265 {
266 case STRING_DELIMITER:
267 case ESCAPE_CHARACTER:
268 case '/':
269 new_string[new_string_pos++] = ch; break;
270 case 'b':
271 new_string[new_string_pos++] = '\b'; break;
272 case 'f':
273 new_string[new_string_pos++] = '\f'; break;
274 case 'n':
275 new_string[new_string_pos++] = '\n'; break;
276 case 'r':
277 new_string[new_string_pos++] = '\r'; break;
278 case 't':
279 new_string[new_string_pos++] = '\t'; break;
280 case 'u':
281 if (NULL != (s = parse_4_hex_digits (s, &new_string_pos, new_string + new_string_pos, NULL)))
282 break; /* else drop */
283 default:
284 goto return_application_error;
285 }
286 }
287
288 if (bstring_lenp != NULL)
289 *bstring_lenp = (is_binary_string ? new_string_len : 0);
290
291 new_string[new_string_pos] = 0;
292 return new_string;
293
294 return_application_error:
295 /* Since any JSon_Parse_Error should already have been recognized
296 * (by parse_string_length_and_move_ptr), something must be wrong here.
297 */
298 SLang_verror (SL_Application_Error, "JSON string being parsed appears to be changing");
299 if (new_string != string_buffer) SLfree (new_string);
300 return NULL;
301 }
302 /*}}}*/
303
parse_and_push_string(Parse_Type * p)304 static int parse_and_push_string (Parse_Type *p) /*{{{*/
305 {
306 unsigned int bstring_len;
307 char *s;
308 char buf[512];
309
310 if (NULL == (s = parse_string (p, buf, sizeof (buf), &bstring_len)))
311 return -1;
312
313 if (bstring_len)
314 {
315 SLang_BString_Type *bstr;
316 int status;
317
318 /* NOTE: parse_string will not use buf for a binary string */
319 if (NULL == (bstr = SLbstring_create_malloced ((unsigned char *)s, bstring_len, 1)))
320 return -1;
321 /* s now belongs to bstr */
322
323 status = SLang_push_bstring (bstr);
324 SLbstring_free (bstr);
325 return status;
326 }
327
328 if (s != buf)
329 return SLang_push_malloced_string (s); /* frees s upon return */
330
331 return SLang_push_string (buf);
332 }
333 /*}}}*/
334
parse_and_push_number(Parse_Type * p)335 static int parse_and_push_number (Parse_Type *p) /*{{{*/
336 {
337 char *s = p->ptr, ch;
338 int is_int = 1, result;
339
340 if (*s == '-')
341 s++;
342 while ('0' <= *s && *s <= '9')
343 s++;
344 if (*s == '.')
345 {
346 is_int = 0;
347 s++;
348 while ('0' <= *s && *s <= '9')
349 s++;
350 }
351 if (*s == 'e' || *s == 'E')
352 {
353 is_int = 0;
354 s++;
355 if (*s == '+' || *s == '-')
356 s++;
357 while ('0' <= *s && *s <= '9')
358 s++;
359 }
360
361 ch = *s;
362 *s = 0;
363 errno = 0;
364 result = is_int ?
365 #ifdef HAVE_LONG_LONG
366 SLang_push_long_long (strtoll (p->ptr, NULL, 10))
367 #else
368 SLang_push_long (strtol (p->ptr, NULL, 10))
369 #endif
370 : SLang_push_double (strtod (p->ptr, NULL));
371 if (errno == ERANGE)
372 {
373 SLang_verror (Json_Parse_Error,
374 is_int
375 ? "Integer value is too large (%s)"
376 : "Numeric value is too large (%s)",
377 p->ptr);
378 }
379
380 *s = ch;
381 p->ptr = s;
382 return result;
383 }
384 /*}}}*/
385
parse_and_push_literal(Parse_Type * p)386 static int parse_and_push_literal (Parse_Type *p) /*{{{*/
387 {
388 char *s = p->ptr;
389
390 if (0 == strncmp (s, "true", 4))
391 {
392 p->ptr += 4;
393 return SLang_push_uchar (1);
394 }
395
396 if (0 == strncmp (s, "false", 5))
397 {
398 p->ptr += 5;
399 return SLang_push_uchar (0);
400 }
401
402 if (0 == strncmp (s, "null", 4))
403 {
404 p->ptr += 4;
405 return SLang_push_null ();
406 }
407
408 SLang_verror (Json_Parse_Error, "Unexpected character " DESCRIBE_CHAR_FMT " seen while parsing a JSON value", DESCRIBE_CHAR(*s));
409 return -1;
410 }
411 /*}}}*/
412
413 static int parse_and_push_object_as_struct (Parse_Type *, int);
414 #if 0
415 static int parse_and_push_object_as_assoc (Parse_Type *, int);
416 #endif
417 static int parse_and_push_array (Parse_Type *, int);
parse_and_push_value(Parse_Type * p,int only_toplevel_values)418 static int parse_and_push_value (Parse_Type *p, int only_toplevel_values) /*{{{*/
419 {
420 int ret;
421
422 skip_white (p);
423
424 if (! only_toplevel_values)
425 {
426 if (skip_char (p, STRING_DELIMITER))
427 return parse_and_push_string (p);
428 switch (*p->ptr)
429 {
430 case '-':
431 case '0': case '1': case '2': case '3': case '4':
432 case '5': case '6': case '7': case '8': case '9':
433 return parse_and_push_number (p);
434 case 'f':
435 case 't':
436 case 'n':
437 return parse_and_push_literal (p);
438 }
439 }
440 if (p->depth > Max_Recursion_Depth)
441 {
442 SLang_verror (Json_Parse_Error, "json text exceeds maximum nesting level of %d", Max_Recursion_Depth);
443 return -1;
444 }
445
446 if (skip_char (p, BEGIN_OBJECT))
447 {
448 p->depth++;
449 ret = parse_and_push_object_as_struct (p, only_toplevel_values);
450 p->depth--;
451 return ret;
452 }
453
454 if (skip_char (p, BEGIN_ARRAY))
455 {
456 p->depth++;
457 ret = parse_and_push_array (p, only_toplevel_values);
458 p->depth--;
459 return ret;
460 }
461
462 SLang_verror (Json_Parse_Error, (only_toplevel_values
463 ? "Unexpected character " DESCRIBE_CHAR_FMT " seen while parsing JSON data (must be an object or an array)"
464 : "Unexpected character " DESCRIBE_CHAR_FMT " seen while parsing a JSON value"
465 ), DESCRIBE_CHAR(*p->ptr));
466 return -1;
467 }
468 /*}}}*/
469
470 #if 0
471 static int parse_and_push_object_as_assoc (Parse_Type *p, int toplevel) /*{{{*/
472 {
473 SLang_Assoc_Array_Type *assoc;
474 char buf[512];
475
476 if (NULL == (assoc = SLang_create_assoc (SLANG_ANY_TYPE, 0)))
477 return -1;
478
479 skip_white (p);
480 if (! looking_at (p, END_OBJECT)) do
481 {
482 char *keyword;
483 char *str;
484
485 skip_white (p);
486 if (! skip_char (p, STRING_DELIMITER))
487 {
488 SLang_verror (Json_Parse_Error, "Expected a string while parsing a JSON object, found " DESCRIBE_CHAR_FMT, DESCRIBE_CHAR(*p->ptr));
489 goto return_error;
490 }
491
492 str = parse_string (p, buf, sizeof (buf), NULL); /* ignoring binary strings */
493 if (str == NULL)
494 goto return_error;
495
496 keyword = SLang_create_slstring (str);
497 if (str != buf)
498 SLfree (str);
499
500 if (keyword == NULL)
501 goto return_error;
502
503 skip_white (p);
504 if (! skip_char (p, NAME_SEPARATOR))
505 {
506 SLang_verror (Json_Parse_Error, "Expected a '%c' while parsing a JSON object, found " DESCRIBE_CHAR_FMT,
507 NAME_SEPARATOR, DESCRIBE_CHAR(*p->ptr));
508 SLang_free_slstring (keyword);
509 goto return_error;
510 }
511
512 if ((-1 == parse_and_push_value (p, 0))
513 || (-1 == SLang_assoc_put (assoc, keyword)))
514 {
515 SLang_free_slstring (keyword);
516 goto return_error;
517 }
518
519 SLang_free_slstring (keyword);
520 skip_white (p);
521 }
522 while (skip_char (p, VALUE_SEPARATOR));
523
524 if (skip_char (p, END_OBJECT))
525 {
526 skip_white (p);
527 if (! toplevel || looking_at (p, 0))
528 return SLang_push_assoc (assoc, 1);
529
530 SLang_verror (Json_Parse_Error, "Expected end of input after parsing JSON object, found " DESCRIBE_CHAR_FMT, DESCRIBE_CHAR(*p->ptr));
531 }
532 else
533 {
534 if (looking_at (p, 0))
535 SLang_verror (Json_Parse_Error, "Unexpected end of input seen while parsing a JSON object");
536 else
537 SLang_verror (Json_Parse_Error, "Expected '%c' or '%c' while parsing a JSON object, found " DESCRIBE_CHAR_FMT,
538 VALUE_SEPARATOR, END_OBJECT, DESCRIBE_CHAR(*p->ptr));
539 }
540
541 return_error:
542 SLang_free_assoc (assoc);
543 return -1;
544 }
545 /*}}}*/
546 #endif
547
free_string_array(char ** sp,unsigned int n)548 static void free_string_array (char **sp, unsigned int n)
549 {
550 if (sp == NULL)
551 return;
552
553 while (n > 0)
554 {
555 n--;
556 SLang_free_slstring (sp[n]);
557 }
558 SLfree ((char *)sp);
559 }
560
561 /* This has table implementation does not copy the strings */
562 #define HASH_TABLE_SIZE 601
563 typedef struct String_Hash_Elem_Type
564 {
565 SLstr_Type *string; /* not copied! */
566 unsigned int val;
567 struct String_Hash_Elem_Type *next;
568 }
569 String_Hash_Elem_Type;
570
571 typedef struct
572 {
573 String_Hash_Elem_Type hash_table[HASH_TABLE_SIZE];
574 unsigned int num_strings;
575 unsigned int num_collisions;
576 }
577 String_Hash_Type;
578
create_string_hash(void)579 static String_Hash_Type *create_string_hash (void)
580 {
581 String_Hash_Type *h;
582 if (NULL == (h = (String_Hash_Type *)SLmalloc(sizeof(String_Hash_Type))))
583 return NULL;
584 memset ((char *)h, 0, sizeof(String_Hash_Type));
585 return h;
586 }
587
588 /* returns -1 upon failure, 0 if string added, 1 if already there */
add_string_to_hash(String_Hash_Type * h,char * s,unsigned int val,unsigned int * valp)589 static int add_string_to_hash (String_Hash_Type *h, char *s, unsigned int val, unsigned int *valp)
590 {
591 SLstr_Hash_Type hash;
592 String_Hash_Elem_Type *e, *e1;
593
594 hash = SLcompute_string_hash (s);
595 e = &h->hash_table[hash % HASH_TABLE_SIZE];
596 if (e->string == NULL)
597 {
598 e->string = s;
599 *valp = e->val = val;
600 h->num_strings++;
601 return 0;
602 }
603
604 while (1)
605 {
606 if (e->string == s)
607 {
608 *valp = e->val;
609 return 1;
610 }
611 if (e->next == NULL)
612 break;
613 e = e->next;
614 }
615
616 e1 = (String_Hash_Elem_Type *)SLmalloc (sizeof (String_Hash_Elem_Type));
617 if (e1 == NULL)
618 return -1;
619
620 e1->string = s;
621 *valp = e1->val = val;
622 e1->next = NULL;
623 e->next = e1;
624 h->num_strings++;
625 h->num_collisions++;
626 return 0;
627 }
628
free_string_hash(String_Hash_Type * h)629 static void free_string_hash (String_Hash_Type *h)
630 {
631 String_Hash_Elem_Type *e, *emax;
632 unsigned int num_collisions;
633
634 if (h == NULL)
635 return;
636
637 e = h->hash_table;
638 emax = e + HASH_TABLE_SIZE;
639 num_collisions = h->num_collisions;
640 while (num_collisions && (e < emax))
641 {
642 String_Hash_Elem_Type *e1;
643 if (e->next == NULL)
644 {
645 e++;
646 continue;
647 }
648 e1 = e->next;
649 while (e1 != NULL)
650 {
651 String_Hash_Elem_Type *e2 = e1->next;
652 SLfree ((char *)e1);
653 num_collisions--;
654 e1 = e2;
655 }
656 e++;
657 }
658 SLfree ((char *)h);
659 }
660
parse_and_push_object_as_struct(Parse_Type * p,int toplevel)661 static int parse_and_push_object_as_struct (Parse_Type *p, int toplevel) /*{{{*/
662 {
663 char buf[512];
664 unsigned int num_fields, max_fields;
665 char **fields;
666 String_Hash_Type *h = NULL;
667
668 max_fields = 16;
669 num_fields = 0;
670 if ((NULL == (fields = (char **)SLmalloc (max_fields * sizeof (char *))))
671 || (NULL == (h = create_string_hash ())))
672 goto return_error;
673
674 skip_white (p);
675 if (! looking_at (p, END_OBJECT)) do
676 {
677 char *keyword;
678 char *str;
679 int status;
680 unsigned int idx;
681
682 skip_white (p);
683 if (! skip_char (p, STRING_DELIMITER))
684 {
685 SLang_verror (Json_Parse_Error, "Expected a string while parsing a JSON object, found " DESCRIBE_CHAR_FMT, DESCRIBE_CHAR(*p->ptr));
686 goto return_error;
687 }
688
689 str = parse_string (p, buf, sizeof (buf), NULL); /* ignoring binary strings */
690 if (str == NULL)
691 goto return_error;
692
693 keyword = SLang_create_slstring (str);
694 if (str != buf)
695 SLfree (str);
696
697 if (keyword == NULL)
698 goto return_error;
699
700 if (-1 == (status = add_string_to_hash (h, keyword, num_fields, &idx)))
701 goto return_error;
702
703 if (status == 0)
704 {
705 if (num_fields == max_fields)
706 {
707 char **new_fields;
708 unsigned int new_max_fields = max_fields + 32;
709
710 if (NULL == (new_fields = (char **) SLrealloc ((char *)fields, new_max_fields*sizeof(char *))))
711 {
712 SLang_free_slstring (keyword);
713 goto return_error;
714 }
715 fields = new_fields;
716 max_fields = new_max_fields;
717 }
718 fields[num_fields++] = keyword;
719 }
720
721 skip_white (p);
722 if (! skip_char (p, NAME_SEPARATOR))
723 {
724 SLang_verror (Json_Parse_Error, "Expected a '%c' while parsing a JSON object, found " DESCRIBE_CHAR_FMT,
725 NAME_SEPARATOR, DESCRIBE_CHAR(*p->ptr));
726 goto return_error;
727 }
728
729
730 if (-1 == parse_and_push_value (p, 0))
731 goto return_error;
732
733 if (status == 1)
734 {
735 /* keyword already exists -- update value */
736 if ((-1 == SLstack_exch (0, num_fields - idx))
737 || (-1 == SLdo_pop ()))
738 goto return_error;
739
740 }
741 skip_white (p);
742 }
743 while (skip_char (p, VALUE_SEPARATOR));
744
745 if (skip_char (p, END_OBJECT))
746 {
747 skip_white (p);
748 if (! toplevel || looking_at (p, 0))
749 {
750 SLang_Struct_Type *s;
751
752 if (NULL == (s = SLang_create_struct (fields, num_fields)))
753 goto return_error;
754
755 if ((-1 == SLang_pop_struct_fields (s, num_fields))
756 || (-1 == SLang_push_struct (s)))
757 {
758 SLang_free_struct (s);
759 goto return_error;
760 }
761 SLang_free_struct (s);
762 free_string_hash (h);
763 free_string_array (fields, num_fields);
764 return 0;
765 }
766
767 SLang_verror (Json_Parse_Error, "Expected end of input after parsing JSON object, found " DESCRIBE_CHAR_FMT, DESCRIBE_CHAR(*p->ptr));
768 }
769 else
770 {
771 if (looking_at (p, 0))
772 SLang_verror (Json_Parse_Error, "Unexpected end of input seen while parsing a JSON object");
773 else
774 SLang_verror (Json_Parse_Error, "Expected '%c' or '%c' while parsing a JSON object, found " DESCRIBE_CHAR_FMT,
775 VALUE_SEPARATOR, END_OBJECT, DESCRIBE_CHAR(*p->ptr));
776 }
777
778 return_error:
779 free_string_array (fields, num_fields);
780 free_string_hash (h);
781 return -1;
782 }
783 /*}}}*/
784
parse_and_push_array(Parse_Type * p,int toplevel)785 static int parse_and_push_array (Parse_Type *p, int toplevel) /*{{{*/
786 {
787 SLang_List_Type *list = SLang_create_list (8); /* let's start with 8 elements */
788
789 if (list == NULL)
790 return -1;
791
792 skip_white (p);
793 if (! looking_at (p, END_ARRAY)) do
794 {
795 if ((-1 == parse_and_push_value (p, 0))
796 || (-1 == SLang_list_append (list, -1)))
797 goto return_error;
798 skip_white (p);
799 }
800 while (skip_char (p, VALUE_SEPARATOR));
801
802 if (skip_char (p, END_ARRAY))
803 {
804 skip_white (p);
805 if (! toplevel || looking_at (p, 0))
806 return SLang_push_list (list, 1);
807
808 SLang_verror (Json_Parse_Error, "Expected end of input after parsing JSON array, found " DESCRIBE_CHAR_FMT, DESCRIBE_CHAR(*p->ptr));
809 }
810 else
811 {
812 if (looking_at (p, 0))
813 SLang_verror (Json_Parse_Error, "Unexpected end of input seen while parsing a JSON array");
814 else
815 SLang_verror (Json_Parse_Error, "Expected '%c' or '%c' while parsing a JSON array, found " DESCRIBE_CHAR_FMT,
816 VALUE_SEPARATOR, END_ARRAY, DESCRIBE_CHAR(*p->ptr));
817 }
818
819 return_error:
820 SLang_free_list (list);
821 return -1;
822 }
823 /*}}}*/
824
parse_start(char * input_string)825 static void parse_start (char *input_string) /*{{{*/
826 {
827 Parse_Type pbuf, *p = &pbuf;
828 memset ((char *)p, 0, sizeof (Parse_Type));
829 p->ptr = input_string;
830
831 if ((NULL == input_string)
832 || (0 == *input_string))
833 SLang_verror (Json_Parse_Error, "Unexpected empty input string");
834 else
835 parse_and_push_value (p, 1);
836 }
837 /*}}}*/
838
json_decode(void)839 static void json_decode (void) /*{{{*/
840 {
841 char *buffer;
842
843 if ((SLang_Num_Function_Args != 1)
844 || (-1 == SLpop_string (&buffer)))
845 {
846 SLang_verror (SL_Usage_Error, "Usage: json_decode (String_Type json_text)");
847 return;
848 }
849 parse_start (buffer);
850 SLfree (buffer);
851 }
852 /*}}}*/
853
854 /*{{{ json_generate_string implementation and support functions */
855
856 static unsigned int Len_Map[128] = /*{{{*/
857 {
858 6,6,6,6,6,6,6,6,
859 2,2,2,6,2,2,6,6,
860 6,6,6,6,6,6,6,6,
861 6,6,6,6,6,6,6,6,
862 1,1,2,1,1,1,1,1,
863 1,1,1,1,1,1,1,1,
864 1,1,1,1,1,1,1,1,
865 1,1,1,1,1,1,1,1,
866 1,1,1,1,1,1,1,1,
867 1,1,1,1,1,1,1,1,
868 1,1,1,1,1,1,1,1,
869 1,1,1,1,2,1,1,1,
870 1,1,1,1,1,1,1,1,
871 1,1,1,1,1,1,1,1,
872 1,1,1,1,1,1,1,1,
873 1,1,1,1,1,1,1,6
874 };
875 /*}}}*/
876
877 static char *String_Map[128] = /*{{{*/
878 {
879 "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007",
880 "\\b", "\\t", "\\n", "\\u000B", "\\f", "\\r", "\\u000E", "\\u000F",
881 "\\u0010", "\\u0011", "\\u0012", "\\u0013", "\\u0014", "\\u0015", "\\u0016", "\\u0017",
882 "\\u0018", "\\u0019", "\\u001A", "\\u001B", "\\u001C", "\\u001D", "\\u001E", "\\u001F",
883 " ", "!", "\\\"", "#", "$", "%", "&", "'",
884 "(", ")", "*", "+", ",", "-", ".", "/",
885 "0", "1", "2", "3", "4", "5", "6", "7",
886 "8", "9", ":", ";", "<", "=", ">", "?",
887 "@", "A", "B", "C", "D", "E", "F", "G",
888 "H", "I", "J", "K", "L", "M", "N", "O",
889 "P", "Q", "R", "S", "T", "U", "V", "W",
890 "X", "Y", "Z", "[", "\\\\", "]", "^", "_",
891 "`", "a", "b", "c", "d", "e", "f", "g",
892 "h", "i", "j", "k", "l", "m", "n", "o",
893 "p", "q", "r", "s", "t", "u", "v", "w",
894 "x", "y", "z", "{", "|", "}", "~", "\\u007F"
895 };
896 /*}}}*/
897
898 /* Adapted from SLutf8.c */
is_invalid_or_overlong_utf8(SLuchar_Type * u,unsigned int len)899 static int is_invalid_or_overlong_utf8 (SLuchar_Type *u, unsigned int len)
900 {
901 unsigned int i;
902 unsigned char ch, ch1;
903
904 /* Check for invalid sequences */
905 for (i = 1; i < len; i++)
906 {
907 if ((u[i] & 0xC0) != 0x80)
908 return 1;
909 }
910
911 /* Illegal (overlong) sequences */
912 /* 1100000x (10xxxxxx) */
913 /* 11100000 100xxxxx (10xxxxxx) */
914 /* 11110000 1000xxxx (10xxxxxx 10xxxxxx) */
915 /* 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx) */
916 /* 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx) */
917 ch = *u;
918 if ((ch == 0xC0) || (ch == 0xC1))
919 return 1;
920
921 ch1 = u[1];
922 if (((ch1 & ch) == 0x80)
923 && ((ch == 0xE0)
924 || (ch == 0xF0)
925 || (ch == 0xF8)
926 || (ch == 0xFC)))
927 return 1;
928
929 return 0;
930 }
931
compute_multibyte_char_len(char * p,char * pmax)932 static SLstrlen_Type compute_multibyte_char_len (char *p, char *pmax) /*{{{*/
933 {
934 SLstrlen_Type len;
935 unsigned char ch;
936
937 ch = (unsigned char)*p;
938 len = ((ch & 0xE0) == 0xC0) ? 2 /* (ch & 0b11100000) == 0b11000000 */
939 : ((ch & 0xF0) == 0xE0) ? 3 /* (ch & 0b11110000) == 0b11100000 */
940 : ((ch & 0xF8) == 0xF0) ? 4 /* (ch & 0b11111000) == 0b11110000 */
941 : ((ch & 0xFC) == 0xF8) ? 5 /* (ch & 0b11111100) == 0b11111000 */
942 : 6;
943
944 if (p + len > pmax)
945 return 1;
946
947 if (is_invalid_or_overlong_utf8 ((SLuchar_Type *)p, len))
948 return 1;
949
950 return len;
951 }
952
953 /*}}}*/
954
alloc_encoded_json_string(char * ptr,char * end_of_input_string,SLstrlen_Type * lenp)955 static char *alloc_encoded_json_string (char *ptr, char *end_of_input_string, SLstrlen_Type *lenp) /*{{{*/
956 {
957 SLstrlen_Type len = 2; /* first '"' and last '"' */
958
959 while (ptr < end_of_input_string)
960 {
961 unsigned char ch = (unsigned char) *ptr;
962 if (ch < 0x80)
963 {
964 len += Len_Map[ch];
965 ptr++;
966 continue;
967 }
968
969 len += 6; /* FIXME: Does not handle 0x1UUUU */
970 ptr += compute_multibyte_char_len (ptr, end_of_input_string);
971
972 if (ptr > end_of_input_string)
973 {
974 SLang_verror (Json_Invalid_Json_Error, "Invalid UTF-8 at end of string");
975 return NULL;
976 }
977 }
978
979 *lenp = len;
980 return SLmalloc (len + 1);
981 }
982 /*}}}*/
983
fill_encoded_json_string(char * ptr,char * end_of_input_string,char * dest_ptr)984 static char *fill_encoded_json_string (char *ptr, char *end_of_input_string,
985 char *dest_ptr) /*{{{*/
986 {
987 *dest_ptr++ = STRING_DELIMITER;
988
989 while (ptr < end_of_input_string)
990 {
991 unsigned char ch = *ptr;
992 unsigned int len;
993
994 if (ch < 0x80)
995 {
996 if (1 == (len = Len_Map[ch]))
997 *dest_ptr++ = ch;
998 else
999 {
1000 char *str = String_Map[ch];
1001 while (len--)
1002 *dest_ptr++ = *str++;
1003 }
1004 ptr++;
1005 continue;
1006 }
1007
1008 /* We cannot use SLutf8_decode, since we need to handle invalid_or_overlong_utf8 or ILLEGAL_UNICODE as well. */
1009 len = compute_multibyte_char_len (ptr, end_of_input_string);
1010 if (len == 1)
1011 {
1012 /* Malformed or overlong */
1013 sprintf (dest_ptr, "<%02X>", (unsigned char)*ptr);
1014 dest_ptr += 4;
1015 }
1016 else
1017 { /* stolen from slutf8.c : fast_utf8_decode */
1018 static unsigned char masks[7] = { 0, 0, 0x1F, 0xF, 0x7, 0x3, 0x1 };
1019 SLwchar_Type w = (ch & masks[len]);
1020 SLstrlen_Type i;
1021 for (i = 1; i < len; i++)
1022 w = (w << 6) | (ptr[i] & 0x3F);
1023
1024 if (w > 0xFFFF)
1025 {
1026 /* FIXME: Must be encoded as a pair of UTF-16 surrogates */
1027 memcpy (dest_ptr, ptr, len);
1028 dest_ptr += len;
1029 }
1030 else
1031 {
1032 sprintf (dest_ptr, "\\u%04X", w);
1033 dest_ptr += 6;
1034 }
1035 }
1036 ptr += len;
1037 }
1038 *dest_ptr++ = STRING_DELIMITER;
1039 *dest_ptr = 0;
1040 return dest_ptr;
1041 }
1042 /*}}}*/
1043
json_encode_string(void)1044 static void json_encode_string (void) /*{{{*/
1045 {
1046 SLang_BString_Type *bstring = NULL;
1047 char *string, *encoded_json_string;
1048 SLstrlen_Type len, new_len;
1049
1050 if (SLang_peek_at_stack () == SLANG_BSTRING_TYPE)
1051 {
1052 if (-1 == SLang_pop_bstring (&bstring))
1053 return;
1054
1055 string = (char *)SLbstring_get_pointer (bstring, &len);
1056 }
1057 else
1058 {
1059 if (-1 == SLang_pop_slstring (&string))
1060 {
1061 SLang_verror (SL_Usage_Error, "usage: _json_generate_string (String_Type json_string)");
1062 return;
1063 }
1064 len = strlen (string);
1065 }
1066
1067 if ((encoded_json_string = alloc_encoded_json_string (string, string + len, &new_len)) != NULL)
1068 {
1069 SLang_BString_Type *b;
1070 char *enc_end;
1071
1072 enc_end = fill_encoded_json_string (string, string + len, encoded_json_string);
1073 new_len = enc_end - encoded_json_string;
1074
1075 b = SLbstring_create_malloced ((unsigned char *)encoded_json_string, new_len, 1);
1076 if (b != NULL)
1077 {
1078 (void) SLang_push_bstring (b);
1079 SLbstring_free (b);
1080 }
1081 }
1082
1083 if (bstring != NULL)
1084 SLbstring_free (bstring);
1085 else
1086 SLang_free_slstring (string);
1087 }
1088 /*}}}*/
1089
1090 /*}}}*/
1091
1092 static SLang_Intrin_Fun_Type Module_Intrinsics [] = /*{{{*/
1093 {
1094 MAKE_INTRINSIC_0("json_decode", json_decode, SLANG_VOID_TYPE),
1095 MAKE_INTRINSIC_0("_json_encode_string", json_encode_string, SLANG_VOID_TYPE),
1096 SLANG_END_INTRIN_FUN_TABLE
1097 };
1098 /*}}}*/
1099
1100 static SLang_Intrin_Var_Type Module_Variables [] = /*{{{*/
1101 {
1102 MAKE_VARIABLE("_json_module_version_string", &json_module_version_string, SLANG_STRING_TYPE, 1),
1103 SLANG_END_INTRIN_VAR_TABLE
1104 };
1105 /*}}}*/
1106
1107 static SLang_IConstant_Type Module_Constants [] = /*{{{*/
1108 {
1109 MAKE_ICONSTANT("_json_module_version", JSON_MODULE_VERSION_NUMBER),
1110 SLANG_END_ICONST_TABLE
1111 };
1112 /*}}}*/
1113
init_json_module_ns(char * ns_name)1114 int init_json_module_ns (char *ns_name) /*{{{*/
1115 {
1116 SLang_NameSpace_Type *ns = SLns_create_namespace (ns_name);
1117 if (ns == NULL)
1118 return -1;
1119
1120 if ((Json_Parse_Error == -1)
1121 && (-1 == (Json_Parse_Error = SLerr_new_exception (SL_RunTime_Error, "Json_Parse_Error", "JSON Parse Error"))))
1122 return -1;
1123
1124 if ((Json_Invalid_Json_Error == -1)
1125 && (-1 == (Json_Invalid_Json_Error = SLerr_new_exception (SL_RunTime_Error, "Json_Invalid_Json_Error", "Invalid JSON Error"))))
1126 return -1;
1127
1128 if ((-1 == SLns_add_intrin_fun_table (ns, Module_Intrinsics, NULL))
1129 || (-1 == SLns_add_intrin_var_table (ns, Module_Variables, NULL))
1130 || (-1 == SLns_add_iconstant_table (ns, Module_Constants, NULL)))
1131 return -1;
1132
1133 return 0;
1134 }
1135 /*}}}*/
1136
deinit_json_module(void)1137 void deinit_json_module (void) /*{{{*/
1138 {
1139 /* This function is optional */
1140 }
1141 /*}}}*/
1142