1 /* JSON trees 2 Copyright (C) 2017-2024 Free Software Foundation, Inc. 3 Contributed by David Malcolm <dmalcolm (at) redhat.com>. 4 5 This file is part of GCC. 6 7 GCC is free software; you can redistribute it and/or modify it under 8 the terms of the GNU General Public License as published by the Free 9 Software Foundation; either version 3, or (at your option) any later 10 version. 11 12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY 13 WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with GCC; see the file COPYING3. If not see 19 <http://www.gnu.org/licenses/>. */ 20 21 #include "config.h" 22 #include "system.h" 23 #include "coretypes.h" 24 #include "json.h" 25 #include "pretty-print.h" 26 #include "math.h" 27 #include "selftest.h" 28 29 using namespace json; 30 31 /* Print a JSON string to PP, escaping '"', control characters, 32 and embedded null bytes. 33 The string is required to be UTF-8 encoded. */ 34 35 static void 36 print_escaped_json_string (pretty_printer *pp, 37 const char *utf8_str, 38 size_t len) 39 { 40 pp_character (pp, '"'); 41 for (size_t i = 0; i != len; ++i) 42 { 43 char ch = utf8_str[i]; 44 switch (ch) 45 { 46 case '"': 47 pp_string (pp, "\\\""); 48 break; 49 case '\\': 50 pp_string (pp, "\\\\"); 51 break; 52 case '\b': 53 pp_string (pp, "\\b"); 54 break; 55 case '\f': 56 pp_string (pp, "\\f"); 57 break; 58 case '\n': 59 pp_string (pp, "\\n"); 60 break; 61 case '\r': 62 pp_string (pp, "\\r"); 63 break; 64 case '\t': 65 pp_string (pp, "\\t"); 66 break; 67 case '\0': 68 pp_string (pp, "\\0"); 69 break; 70 default: 71 pp_character (pp, ch); 72 } 73 } 74 pp_character (pp, '"'); 75 } 76 77 /* class json::value. */ 78 79 /* Dump this json::value tree to OUTF. 80 81 The key/value pairs of json::objects are printed in the order 82 in which the keys were originally inserted. */ 83 84 void 85 value::dump (FILE *outf, bool formatted) const 86 { 87 pretty_printer pp; 88 pp_buffer (&pp)->stream = outf; 89 print (&pp, formatted); 90 pp_flush (&pp); 91 } 92 93 /* class json::object, a subclass of json::value, representing 94 an ordered collection of key/value pairs. */ 95 96 /* json:object's dtor. */ 97 98 object::~object () 99 { 100 for (map_t::iterator it = m_map.begin (); it != m_map.end (); ++it) 101 { 102 free (const_cast <char *>((*it).first)); 103 delete ((*it).second); 104 } 105 } 106 107 /* Implementation of json::value::print for json::object. */ 108 109 void 110 object::print (pretty_printer *pp, bool formatted) const 111 { 112 pp_character (pp, '{'); 113 if (formatted) 114 pp_indentation (pp) += 1; 115 116 /* Iterate in the order that the keys were inserted. */ 117 unsigned i; 118 const char *key; 119 FOR_EACH_VEC_ELT (m_keys, i, key) 120 { 121 if (i > 0) 122 { 123 pp_string (pp, ","); 124 if (formatted) 125 { 126 pp_newline (pp); 127 pp_indent (pp); 128 } 129 else 130 pp_space (pp); 131 } 132 map_t &mut_map = const_cast<map_t &> (m_map); 133 value *value = *mut_map.get (key); 134 print_escaped_json_string (pp, key, strlen (key)); 135 pp_string (pp, ": "); 136 const int indent = strlen (key) + 4; 137 if (formatted) 138 pp_indentation (pp) += indent; 139 value->print (pp, formatted); 140 if (formatted) 141 pp_indentation (pp) -= indent; 142 } 143 if (formatted) 144 pp_indentation (pp) -= 1; 145 pp_character (pp, '}'); 146 } 147 148 /* Set the json::value * for KEY, taking ownership of V 149 (and taking a copy of KEY if necessary). */ 150 151 void 152 object::set (const char *key, value *v) 153 { 154 gcc_assert (key); 155 gcc_assert (v); 156 157 value **ptr = m_map.get (key); 158 if (ptr) 159 { 160 /* If the key is already present, delete the existing value 161 and overwrite it. */ 162 delete *ptr; 163 *ptr = v; 164 } 165 else 166 { 167 /* If the key wasn't already present, take a copy of the key, 168 and store the value. */ 169 char *owned_key = xstrdup (key); 170 m_map.put (owned_key, v); 171 m_keys.safe_push (owned_key); 172 } 173 } 174 175 /* Get the json::value * for KEY. 176 177 The object retains ownership of the value. */ 178 179 value * 180 object::get (const char *key) const 181 { 182 gcc_assert (key); 183 184 value **ptr = const_cast <map_t &> (m_map).get (key); 185 if (ptr) 186 return *ptr; 187 else 188 return NULL; 189 } 190 191 /* Set value of KEY within this object to a JSON 192 string value based on UTF8_VALUE. */ 193 194 void 195 object::set_string (const char *key, const char *utf8_value) 196 { 197 set (key, new json::string (utf8_value)); 198 } 199 200 /* Set value of KEY within this object to a JSON 201 integer value based on V. */ 202 203 void 204 object::set_integer (const char *key, long v) 205 { 206 set (key, new json::integer_number (v)); 207 } 208 209 /* Set value of KEY within this object to a JSON 210 floating point value based on V. */ 211 212 void 213 object::set_float (const char *key, double v) 214 { 215 set (key, new json::float_number (v)); 216 } 217 218 /* Set value of KEY within this object to the JSON 219 literal true or false, based on V. */ 220 221 void 222 object::set_bool (const char *key, bool v) 223 { 224 set (key, new json::literal (v)); 225 } 226 227 /* class json::array, a subclass of json::value, representing 228 an ordered collection of values. */ 229 230 /* json::array's dtor. */ 231 232 array::~array () 233 { 234 unsigned i; 235 value *v; 236 FOR_EACH_VEC_ELT (m_elements, i, v) 237 delete v; 238 } 239 240 /* Implementation of json::value::print for json::array. */ 241 242 void 243 array::print (pretty_printer *pp, bool formatted) const 244 { 245 pp_character (pp, '['); 246 if (formatted) 247 pp_indentation (pp) += 1; 248 unsigned i; 249 value *v; 250 FOR_EACH_VEC_ELT (m_elements, i, v) 251 { 252 if (i) 253 { 254 pp_string (pp, ","); 255 if (formatted) 256 { 257 pp_newline (pp); 258 pp_indent (pp); 259 } 260 else 261 pp_space (pp); 262 } 263 v->print (pp, formatted); 264 } 265 if (formatted) 266 pp_indentation (pp) -= 1; 267 pp_character (pp, ']'); 268 } 269 270 /* Append non-NULL value V to a json::array, taking ownership of V. */ 271 272 void 273 array::append (value *v) 274 { 275 gcc_assert (v); 276 m_elements.safe_push (v); 277 } 278 279 /* class json::float_number, a subclass of json::value, wrapping a double. */ 280 281 /* Implementation of json::value::print for json::float_number. */ 282 283 void 284 float_number::print (pretty_printer *pp, 285 bool formatted ATTRIBUTE_UNUSED) const 286 { 287 char tmp[1024]; 288 snprintf (tmp, sizeof (tmp), "%g", m_value); 289 pp_string (pp, tmp); 290 } 291 292 /* class json::integer_number, a subclass of json::value, wrapping a long. */ 293 294 /* Implementation of json::value::print for json::integer_number. */ 295 296 void 297 integer_number::print (pretty_printer *pp, 298 bool formatted ATTRIBUTE_UNUSED) const 299 { 300 char tmp[1024]; 301 snprintf (tmp, sizeof (tmp), "%ld", m_value); 302 pp_string (pp, tmp); 303 } 304 305 306 /* class json::string, a subclass of json::value. */ 307 308 /* json::string's ctor. */ 309 310 string::string (const char *utf8) 311 { 312 gcc_assert (utf8); 313 m_utf8 = xstrdup (utf8); 314 m_len = strlen (utf8); 315 } 316 317 string::string (const char *utf8, size_t len) 318 { 319 gcc_assert (utf8); 320 m_utf8 = XNEWVEC (char, len); 321 m_len = len; 322 memcpy (m_utf8, utf8, len); 323 } 324 325 /* Implementation of json::value::print for json::string. */ 326 327 void 328 string::print (pretty_printer *pp, 329 bool formatted ATTRIBUTE_UNUSED) const 330 { 331 print_escaped_json_string (pp, m_utf8, m_len); 332 } 333 334 /* class json::literal, a subclass of json::value. */ 335 336 /* Implementation of json::value::print for json::literal. */ 337 338 void 339 literal::print (pretty_printer *pp, 340 bool formatted ATTRIBUTE_UNUSED) const 341 { 342 switch (m_kind) 343 { 344 case JSON_TRUE: 345 pp_string (pp, "true"); 346 break; 347 case JSON_FALSE: 348 pp_string (pp, "false"); 349 break; 350 case JSON_NULL: 351 pp_string (pp, "null"); 352 break; 353 default: 354 gcc_unreachable (); 355 } 356 } 357 358 359 #if CHECKING_P 361 362 namespace selftest { 363 364 /* Selftests. */ 365 366 /* Verify that JV->print () prints EXPECTED_JSON. */ 367 368 static void 369 assert_print_eq (const location &loc, 370 const json::value &jv, 371 bool formatted, 372 const char *expected_json) 373 { 374 pretty_printer pp; 375 jv.print (&pp, formatted); 376 ASSERT_STREQ_AT (loc, expected_json, pp_formatted_text (&pp)); 377 } 378 379 #define ASSERT_PRINT_EQ(JV, FORMATTED, EXPECTED_JSON) \ 380 assert_print_eq (SELFTEST_LOCATION, JV, FORMATTED, EXPECTED_JSON) 381 382 /* Verify that object::get works as expected. */ 383 384 static void 385 test_object_get () 386 { 387 object obj; 388 value *val = new json::string ("value"); 389 obj.set ("foo", val); 390 ASSERT_EQ (obj.get ("foo"), val); 391 ASSERT_EQ (obj.get ("not-present"), NULL); 392 } 393 394 /* Verify that JSON objects are written correctly. */ 395 396 static void 397 test_writing_objects () 398 { 399 object obj; 400 obj.set_string ("foo", "bar"); 401 obj.set_string ("baz", "quux"); 402 obj.set_string ("\"\\\b\f\n\r\t", "value for awkward key"); 403 404 /* This test relies on json::object writing out key/value pairs 405 in key-insertion order. */ 406 ASSERT_PRINT_EQ (obj, true, 407 "{\"foo\": \"bar\",\n" 408 " \"baz\": \"quux\",\n" 409 " \"\\\"\\\\\\b\\f\\n\\r\\t\": \"value for awkward key\"}"); 410 ASSERT_PRINT_EQ (obj, false, 411 "{\"foo\": \"bar\", \"baz\": \"quux\"" 412 ", \"\\\"\\\\\\b\\f\\n\\r\\t\": \"value for awkward key\"}"); 413 } 414 415 /* Verify that JSON arrays are written correctly. */ 416 417 static void 418 test_writing_arrays () 419 { 420 array arr; 421 ASSERT_PRINT_EQ (arr, true, "[]"); 422 423 arr.append (new json::string ("foo")); 424 ASSERT_PRINT_EQ (arr, true, "[\"foo\"]"); 425 426 arr.append (new json::string ("bar")); 427 ASSERT_PRINT_EQ (arr, true, 428 "[\"foo\",\n" 429 " \"bar\"]"); 430 ASSERT_PRINT_EQ (arr, false, 431 "[\"foo\", \"bar\"]"); 432 } 433 434 /* Verify that JSON numbers are written correctly. */ 435 436 static void 437 test_writing_float_numbers () 438 { 439 ASSERT_PRINT_EQ (float_number (0), true, "0"); 440 ASSERT_PRINT_EQ (float_number (42), true, "42"); 441 ASSERT_PRINT_EQ (float_number (-100), true, "-100"); 442 ASSERT_PRINT_EQ (float_number (123456789), true, "1.23457e+08"); 443 } 444 445 static void 446 test_writing_integer_numbers () 447 { 448 ASSERT_PRINT_EQ (integer_number (0), true, "0"); 449 ASSERT_PRINT_EQ (integer_number (42), true, "42"); 450 ASSERT_PRINT_EQ (integer_number (-100), true, "-100"); 451 ASSERT_PRINT_EQ (integer_number (123456789), true, "123456789"); 452 ASSERT_PRINT_EQ (integer_number (-123456789), true, "-123456789"); 453 } 454 455 /* Verify that JSON strings are written correctly. */ 456 457 static void 458 test_writing_strings () 459 { 460 string foo ("foo"); 461 ASSERT_PRINT_EQ (foo, true, "\"foo\""); 462 463 string contains_quotes ("before \"quoted\" after"); 464 ASSERT_PRINT_EQ (contains_quotes, true, "\"before \\\"quoted\\\" after\""); 465 466 const char data[] = {'a', 'b', 'c', 'd', '\0', 'e', 'f'}; 467 string not_terminated (data, 3); 468 ASSERT_PRINT_EQ (not_terminated, true, "\"abc\""); 469 string embedded_null (data, sizeof data); 470 ASSERT_PRINT_EQ (embedded_null, true, "\"abcd\\0ef\""); 471 } 472 473 /* Verify that JSON literals are written correctly. */ 474 475 static void 476 test_writing_literals () 477 { 478 ASSERT_PRINT_EQ (literal (JSON_TRUE), true, "true"); 479 ASSERT_PRINT_EQ (literal (JSON_FALSE), true, "false"); 480 ASSERT_PRINT_EQ (literal (JSON_NULL), true, "null"); 481 482 ASSERT_PRINT_EQ (literal (true), true, "true"); 483 ASSERT_PRINT_EQ (literal (false), true, "false"); 484 } 485 486 /* Verify that nested values are formatted correctly when written. */ 487 488 static void 489 test_formatting () 490 { 491 object obj; 492 object *child = new object; 493 object *grandchild = new object; 494 495 obj.set_string ("str", "bar"); 496 obj.set ("child", child); 497 obj.set_integer ("int", 42); 498 499 child->set ("grandchild", grandchild); 500 child->set_integer ("int", 1776); 501 502 array *arr = new array; 503 for (int i = 0; i < 3; i++) 504 arr->append (new integer_number (i)); 505 grandchild->set ("arr", arr); 506 grandchild->set_integer ("int", 1066); 507 508 /* This test relies on json::object writing out key/value pairs 509 in key-insertion order. */ 510 ASSERT_PRINT_EQ (obj, true, 511 ("{\"str\": \"bar\",\n" 512 " \"child\": {\"grandchild\": {\"arr\": [0,\n" 513 " 1,\n" 514 " 2],\n" 515 " \"int\": 1066},\n" 516 " \"int\": 1776},\n" 517 " \"int\": 42}")); 518 ASSERT_PRINT_EQ (obj, false, 519 ("{\"str\": \"bar\", \"child\": {\"grandchild\":" 520 " {\"arr\": [0, 1, 2], \"int\": 1066}," 521 " \"int\": 1776}, \"int\": 42}")); 522 } 523 524 /* Run all of the selftests within this file. */ 525 526 void 527 json_cc_tests () 528 { 529 test_object_get (); 530 test_writing_objects (); 531 test_writing_arrays (); 532 test_writing_float_numbers (); 533 test_writing_integer_numbers (); 534 test_writing_strings (); 535 test_writing_literals (); 536 test_formatting (); 537 } 538 539 } // namespace selftest 540 541 #endif /* #if CHECKING_P */ 542