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@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