Home | History | Annotate | Line # | Download | only in keama
      1 /*	$NetBSD: json.c,v 1.3 2022/04/03 01:10:59 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 2017-2022 Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * Permission to use, copy, modify, and distribute this software for any
      7  * purpose with or without fee is hereby granted, provided that the above
      8  * copyright notice and this permission notice appear in all copies.
      9  *
     10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
     11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
     13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     16  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17  *
     18  *   Internet Systems Consortium, Inc.
     19  *   PO Box 360
     20  *   Newmarket, NH 03857 USA
     21  *   <info (at) isc.org>
     22  *   https://www.isc.org/
     23  *
     24  */
     25 
     26 #include <sys/cdefs.h>
     27 __RCSID("$NetBSD: json.c,v 1.3 2022/04/03 01:10:59 christos Exp $");
     28 
     29 /* From Kea src/lib/cc/data.cc fromJSON() */
     30 
     31 #include "keama.h"
     32 
     33 #include <stdlib.h>
     34 #include <string.h>
     35 
     36 struct element *
     37 json_parse(struct parse *cfile)
     38 {
     39 	struct element *elem;
     40 	const char *val;
     41 	enum dhcp_token token;
     42 
     43 	elem = create();
     44 	stackPush(cfile, elem);
     45 	cfile->stack[0] = elem;
     46 	cfile->stack_top = 0;
     47 
     48 	token = next_token(&val, NULL, cfile);
     49 	switch (token) {
     50 	case NUMBER:
     51 		elem = createInt(atoll(val));
     52 		TAILQ_CONCAT(&elem->comments, &cfile->comments);
     53 		break;
     54 	case STRING:
     55 		elem = createString(makeString(-1, val));
     56 		TAILQ_CONCAT(&elem->comments, &cfile->comments);
     57 		break;
     58 	case NAME:
     59 		if (strcmp(val, "null") == 0)
     60 			elem = createNull();
     61 		else if (strcmp(val, "true") == 0)
     62 			elem = createBool(ISC_TRUE);
     63 		else if (strcmp(val, "false") == 0) {
     64 			elem = createBool(ISC_FALSE);
     65 			elem->skip = ISC_TRUE;
     66 		} else
     67 			parse_error(cfile, "unknown name %s", val);
     68 		TAILQ_CONCAT(&elem->comments, &cfile->comments);
     69 		break;
     70 	case LBRACKET:
     71 		elem = json_list_parse(cfile);
     72 		break;
     73 	case LBRACE:
     74 		elem = json_map_parse(cfile);
     75 		break;
     76 	case END_OF_FILE:
     77 		parse_error(cfile, "unexpected end of file");
     78 	default:
     79 		parse_error(cfile, "unexpected %s", val);
     80 	}
     81 	return elem;
     82 }
     83 
     84 struct element *
     85 json_list_parse(struct parse *cfile)
     86 {
     87 	struct element *list;
     88 	struct element *item;
     89 	const char *val;
     90 	enum dhcp_token token;
     91 	isc_boolean_t done = ISC_FALSE;
     92 
     93 	list = createList();
     94 	TAILQ_CONCAT(&list->comments, &cfile->comments);
     95 	stackPush(cfile, list);
     96 	do {
     97 		token = peek_token(&val, NULL, cfile);
     98 		switch (token) {
     99 		case RBRACKET:
    100 			done = ISC_TRUE;
    101 			break;
    102 		case END_OF_FILE:
    103 			parse_error(cfile, "unexpected end of file");
    104 		case COMMA:
    105 			skip_token(&val, NULL, cfile);
    106 			if (listSize(list) == 0)
    107 				parse_error(cfile, "unexpected ','");
    108 			item = json_parse(cfile);
    109 			listPush(list, item);
    110 			break;
    111 		default:
    112 			if (listSize(list) > 0)
    113 				parse_error(cfile, "expected ','");
    114 			item = json_parse(cfile);
    115 			listPush(list, item);
    116 			break;
    117 		}
    118 	} while (!done);
    119 	skip_token(&val, NULL, cfile);
    120 	cfile->stack_top--;
    121 	return list;
    122 }
    123 
    124 struct element *
    125 json_map_parse(struct parse *cfile)
    126 {
    127 	struct element *map;
    128 	struct element *item;
    129 	const char *val;
    130 	const char *key;
    131 	enum dhcp_token token;
    132 	isc_boolean_t done = ISC_FALSE;
    133 
    134 	map = createMap();
    135 	TAILQ_CONCAT(&map->comments, &cfile->comments);
    136 	stackPush(cfile, map);
    137 	do {
    138 		token = peek_token(&val, NULL, cfile);
    139 		switch (token) {
    140 		case RBRACE:
    141 			done = ISC_TRUE;
    142 			break;
    143 		case END_OF_FILE:
    144 			parse_error(cfile, "unexpected end of file");
    145 		case COMMA:
    146 			skip_token(&val, NULL, cfile);
    147 			if (mapSize(map) == 0)
    148 				parse_error(cfile, "unexpected ','");
    149 			token = next_token(&val, NULL, cfile);
    150 			if (token != STRING)
    151 				parse_error(cfile, "unexpected %s, "
    152 					    "expected \"key\":value", val);
    153 			key = strdup(val);
    154 			token = next_token(&val, NULL, cfile);
    155 			if (token != COLON)
    156 				parse_error(cfile, "unexpected %s, "
    157 					    "expected ':'", val);
    158 			item = json_parse(cfile);
    159 			mapSet(map, item, key);
    160 			break;
    161 		case STRING:
    162 			skip_token(&val, NULL, cfile);
    163 			if (mapSize(map) > 0)
    164 				parse_error(cfile, "unexpected \"%s\", "
    165 					    "expected ','", val);
    166 			key = strdup(val);
    167 			token = next_token(&val, NULL, cfile);
    168 			if (token != COLON)
    169 				parse_error(cfile, "unexpected %s, "
    170 					    "expected ':'", val);
    171 			item = json_parse(cfile);
    172 			mapSet(map, item, key);
    173 			break;
    174 		default:
    175 			if (mapSize(map) == 0)
    176 				parse_error(cfile, "unexpected %s, "
    177 					    "expected \"key\":value or '}'",
    178 					    val);
    179 			else
    180 				parse_error(cfile, "unexpected %s, "
    181 					    "expected ',' or '}'", val);
    182 		}
    183 	} while (!done);
    184 	skip_token(&val, NULL, cfile);
    185 	cfile->stack_top--;
    186 	return map;
    187 }
    188