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