1 /* 2 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 #include <vector> 26 #include <iterator> 27 #include <cstring> 28 #include <sys/stat.h> 29 #include <fcntl.h> 30 #include <unistd.h> 31 #include <map> 32 #include <iostream> 33 #include <regex> 34 #include "json.h" 35 #include "buffer_cursor.h" 36 37 38 JSonNode::JSonNode(Type type, JSonObjectNode *parent, std::string name) 39 : type(type), parent(parent), name(name) { 40 } 41 42 bool JSonNode::hasNode(std::string name) { return false; } 43 44 JSonNode *JSonNode::getNode(std::string name) { return nullptr; } 45 46 47 bool JSonNode::isList() { return type == LIST; } 48 bool JSonNode::isObject() { return type == OBJECT; } 49 bool JSonNode::isValue() { return type == VALUE; } 50 51 JSonNode::~JSonNode() = default; 52 53 JSonValueNode::JSonValueNode(JSonObjectNode *parent, std::string name, const JSonValueNode::ValueType valueType, 54 std::string value) 55 : JSonNode( 56 VALUE, parent, std::move(name)), valueType(valueType), value(std::move(value)) { 57 } 58 59 JSonValueNode::~JSonValueNode() = default; 60 61 JSonObjectNode::JSonObjectNode(const JSonNode::Type type, JSonObjectNode *parent, const std::string &name) 62 : JSonNode(type, parent,name) { 63 } 64 65 JSonObjectNode::JSonObjectNode(JSonObjectNode *parent, const std::string &name) 66 : JSonNode(OBJECT, parent,name) { 67 } 68 69 JSonObjectNode::~JSonObjectNode() { 70 for (auto c: childArray) { 71 delete c; 72 } 73 childArray.clear(); 74 nameToChildMap.clear(); 75 } 76 77 JSonNode *JSonObjectNode::add(JSonNode *newOne) { 78 nameToChildMap[newOne->name] = newOne; 79 childArray.push_back(newOne); 80 return newOne; 81 } 82 83 int JSonListNode::size() const { 84 return nameToChildMap.size(); 85 } 86 87 JSonListNode::JSonListNode(JSonObjectNode *parent, std::string name) 88 : JSonObjectNode(JSonNode::Type::LIST, parent, 89 name) { 90 } 91 92 JSonListNode::~JSonListNode() = default; 93 94 95 JSonValueNode *JSonNode::asValue() { 96 return dynamic_cast<JSonValueNode *>(this); 97 } 98 99 JSonListNode *JSonNode::asList() { 100 return dynamic_cast<JSonListNode *>(this); 101 } 102 103 JSonObjectNode *JSonNode::asObject() { 104 return dynamic_cast<JSonObjectNode *>(this); 105 } 106 107 void JSonObjectNode::visit(const JSonNodeVisitor& visitor) { 108 for (auto n: childArray) { 109 visitor(n); 110 } 111 } 112 113 bool JSonObjectNode::hasNode(std::string name) { return nameToChildMap.find(name) != nameToChildMap.end(); } 114 115 JSonNode *JSonObjectNode::getNode(std::string name) { return nameToChildMap[name]; } 116 117 std::string JSonNode::parseString(BufferCursor *cursor) { 118 cursor->advance(); // step over " 119 std::string content; 120 //https://www.json.org/json-en.html 121 while (!cursor->isLookingAt('"')) { 122 if (cursor->isLookingAt('\\')) { 123 cursor->advance(); 124 char c = cursor->ch(); 125 switch (c) { 126 case 'n': content += '\n'; 127 break ; 128 case 'r': content += '\r'; 129 break ; 130 case 't': content += '\t'; 131 break ; 132 case 'b': content += '\b'; 133 break ; 134 case 'f': content += '\f'; 135 break ; 136 case '"': content += '"'; 137 break ; 138 case '/': content += '/'; 139 break ; 140 case '\\': content += '\\'; 141 break ; 142 case 'u': { 143 cursor->advance(); 144 int value = 0; 145 while (cursor->isLookingAtHexDigit()) { 146 c = cursor->ch(); 147 value = value * 16 + (::isdigit(c)) 148 ? c - '0' 149 : (c >= 'a' && c <= 'f') 150 ? c - 'a' + 10 151 : c - 'A' + 10; 152 } 153 if (value < 127) { 154 content += (char) value; 155 } else { 156 std::cerr << "skipping unicode " << std::hex << value << std::endl; 157 std::exit(1); 158 } 159 break; 160 } 161 default: 162 163 std::cerr << "skipping escape of char '" << c << std::endl; 164 content += c; 165 }; 166 } else { 167 content += cursor->ch(); 168 } 169 cursor->advance(); 170 } 171 172 cursor->advance(); // step over " 173 return content; 174 } 175 176 JSonNode *JSonObjectNode::parse(BufferCursor *cursor) { 177 // we are 'passed the open curly' 178 Mark *objectStart = cursor->mark(); 179 cursor->skipWhiteSpaceOrNewLine(); 180 while (!cursor->isLookingAt("}")) { 181 if (cursor->isLookingAt('\"')) { 182 std::string parsedName = JSonNode::parseString(cursor); 183 cursor->skipWhiteSpaceOrNewLine(); 184 if (cursor->isLookingAt(':')) { 185 cursor->advance(); 186 cursor->skipWhiteSpaceOrNewLine(); 187 188 if (cursor->isLookingAt("{")) { 189 cursor->advance(); 190 object(parsedName, [&](auto o) { 191 o->parse(cursor); 192 }); 193 } else if (cursor->isLookingAt("[")) { 194 cursor->advance(); 195 // std::cerr << "into Arr"<<std::endl; 196 list(parsedName, [&](auto l) { 197 l->parse(cursor); 198 }); 199 // std::cerr << "outof Arr"<<std::endl; 200 } else { 201 if (cursor->isLookingAt('\"')) { 202 std::string parsedValue = JSonNode::parseString(cursor); 203 this->string(parsedName, parsedValue); 204 } else if (cursor->isLookingAt("true")) { 205 cursor->stepOver("true"); 206 this->boolean(parsedName, "true"); 207 } else if (cursor->isLookingAt("false")) { 208 cursor->stepOver("false"); 209 this->boolean(parsedName, "false"); 210 } else { 211 Mark *start = cursor->mark(); 212 bool number = true; 213 bool integer = true; 214 bool first = true; 215 bool hasDot = false; 216 while (cursor->isLookingAtAlphaNumOr("_-.")) { 217 number = number && ((first && cursor->isLookingAt('-')) || cursor->isLookingAtDigit() || ( 218 !hasDot && cursor->isLookingAt('.'))); 219 integer = integer && ((first && cursor->isLookingAt('-')) || (cursor->isLookingAtDigit())); 220 hasDot = hasDot | cursor->isLookingAt('.'); 221 cursor->advance(); 222 first = false; 223 } 224 std::string parsedValue = start->str(); 225 if (parsedValue == "x") { 226 std::cerr << "x!" << std::endl; 227 } 228 if (integer) { 229 this->integer(parsedName, parsedValue); 230 } else if (number) { 231 this->number(parsedName, parsedValue); 232 } else { 233 this->string(parsedName, parsedValue); 234 } 235 } 236 } 237 cursor->skipWhiteSpaceOrNewLine(); 238 if (cursor->isLookingAt(",")) { 239 cursor->advance(); 240 cursor->skipWhiteSpaceOrNewLine(); 241 } else if (!cursor->isLookingAt('}')) { 242 std::cerr << "expecting , for }" << std::endl; 243 } 244 } else { 245 std::cerr << "expecting colon name!" << std::endl; 246 } 247 } else { 248 std::cerr << "expecting literal name!" << std::endl; 249 } 250 } 251 cursor->advance(); 252 cursor->skipWhiteSpaceOrNewLine(); 253 return this; 254 } 255 256 JSonNode *JSonListNode::parse(BufferCursor *cursor) { 257 // we are passed the open '[' 258 cursor->skipWhiteSpaceOrNewLine(); 259 260 Mark *listStart = cursor->mark(); 261 cursor->skipWhiteSpaceOrNewLine(); 262 while (!cursor->isLookingAt("]")) { 263 if (cursor->isLookingAt("{")) { 264 cursor->advance(); 265 item([&](auto n) { 266 n->parse(cursor); 267 }); 268 } else if (cursor->isLookingAt("[")) { 269 cursor->advance(); 270 list([&](auto l) { 271 l->parse(cursor); 272 }); 273 } else { 274 if (cursor->isLookingAt('\"')) { 275 std::string parsedValue = JSonNode::parseString(cursor); 276 this->string(parsedValue); 277 } else if (cursor->isLookingAt("true")) { 278 cursor->stepOver("true"); 279 this->boolean("true"); 280 } else if (cursor->isLookingAt("false")) { 281 cursor->stepOver("false"); 282 this->boolean("false"); 283 } else { 284 Mark *start = cursor->mark(); 285 bool number = true; 286 bool integer = true; 287 bool first = true; 288 bool hasDot = false; 289 while (cursor->isLookingAtAlphaNumOr("_-.")) { 290 number = number && ((first && cursor->isLookingAt('-')) || cursor->isLookingAtDigit() || ( 291 !hasDot && cursor->isLookingAt('.'))); 292 integer = integer && ((first && cursor->isLookingAt('-')) || (cursor->isLookingAtDigit())); 293 hasDot = hasDot | cursor->isLookingAt('.'); 294 cursor->advance(); 295 first = false; 296 } 297 std::string parsedValue = start->str(); 298 if (parsedValue == "x") { 299 std::cerr << "x!" << std::endl; 300 } 301 if (integer) { 302 this->integer(parsedValue); 303 } else if (number) { 304 this->number(parsedValue); 305 } else { 306 this->string(parsedValue); 307 } 308 } 309 } 310 311 cursor->skipWhiteSpaceOrNewLine(); 312 if (cursor->isLookingAt(",")) { 313 cursor->advance(); 314 cursor->skipWhiteSpaceOrNewLine(); 315 } else if (!cursor->isLookingAt(']')) { 316 std::cerr << "expecting , for [" << std::endl; 317 } 318 } 319 cursor->advance(); 320 cursor->skipWhiteSpaceOrNewLine(); 321 return this; 322 } 323 324 JSonNode *JSonNode::parse(char *text) { 325 BufferCursor *cursor = new BufferCursor((char *) text); 326 cursor->skipWhiteSpace(); 327 if (cursor->isLookingAt("{")) { 328 cursor->advance(); 329 JSonObjectNode *doc = new JSonObjectNode(nullptr, ""); 330 doc->parse(cursor); 331 return doc; 332 } else if (cursor->isLookingAt("[")) { 333 cursor->advance(); 334 JSonObjectNode *doc = new JSonListNode(nullptr, ""); 335 doc->parse(cursor); 336 return doc; 337 } 338 delete cursor; 339 return nullptr; 340 } 341 342 JSonObjectNode *JSonNode::remove() { 343 return parent->remove(this); 344 } 345 346 JSonNode *JSonNode::collect(std::string s, std::vector<JSonNode *> &list) { 347 std::cout << "collecting " << s << std::endl; 348 if (s == "") { 349 list.push_back(this); 350 } else { 351 auto slashpos = s.find_first_of('/'); 352 std::string head = (slashpos == std::string::npos) ? s : s.substr(0, slashpos); 353 std::string tail = (slashpos == std::string::npos) ? "" : s.substr(slashpos + 1); 354 if (head == "..") { 355 parent->collect(tail, list); 356 } else { 357 if (head[0] == '{') { 358 auto eqpos = head.find_first_of('='); 359 auto tildepos = head.find_first_of('~'); 360 auto ccbracepos = head.find_last_of('}'); 361 auto notpos = head.find_first_of('!'); 362 if (eqpos != std::string::npos && (tildepos == std::string::npos || tildepos > eqpos) && ccbracepos != 363 std::string::npos && ccbracepos > eqpos) { 364 bool invert = (notpos != std::string::npos && notpos + 1 == eqpos); 365 std::string listName = head.substr(1, eqpos - 1 - (invert ? 1 : 0)); 366 std::string re = head.substr(eqpos + 1, ccbracepos - eqpos - 1); 367 JSonObjectNode *node = asObject(); 368 if (node) { 369 auto n = node->nameToChildMap[listName]; 370 if (n && n->isValue()) { 371 std::string svalue = n->asValue()->value; 372 if (invert && svalue != re) { 373 list.push_back(this); 374 } else if (!invert && svalue == re) { 375 list.push_back(this); 376 } 377 } 378 } 379 } else if (tildepos != std::string::npos && (eqpos == std::string::npos || eqpos > tildepos) && 380 ccbracepos != std::string::npos && ccbracepos > tildepos) { 381 bool invert = (notpos != std::string::npos && notpos + 1 == tildepos); 382 std::string listName = head.substr(1, tildepos - 1 - (invert ? 1 : 0)); 383 std::string re = head.substr(tildepos + 1, ccbracepos - tildepos - 1); 384 JSonObjectNode *node = asObject(); 385 if (node) { 386 auto n = node->nameToChildMap[listName]; 387 if (n && n->isValue()) { 388 std::string svalue = n->asValue()->value; 389 std::regex r(re); 390 bool matched = std::regex_match(svalue, r); 391 if (invert && !matched) { 392 list.push_back(this); 393 } else if (!invert && matched) { 394 list.push_back(this); 395 } 396 } 397 } 398 } 399 } else { 400 auto osbracepos = head.find_first_of('['); 401 auto csbracepos = head.find_last_of(']'); 402 if (osbracepos != std::string::npos && csbracepos != std::string::npos && csbracepos > osbracepos) { 403 // we have something akin to map[...] 404 std::string listName = s.substr(0, osbracepos); 405 std::string listSuffix = s.substr(osbracepos + 1, csbracepos - osbracepos - 1); 406 JSonObjectNode *node = asObject(); 407 if (node) { 408 std::regex r(listName); 409 for (auto spair: node->nameToChildMap) { 410 if (std::regex_match(spair.first, r)) { 411 if (tail == "") { 412 spair.second->collect(listSuffix, list); 413 } else { 414 spair.second->collect(listSuffix + "/" + tail, list); 415 } 416 } 417 } 418 } 419 } else { 420 // auto ocbracepos = s.find_first_of('{'); 421 JSonObjectNode *node = asObject(); 422 if (node) { 423 std::regex r(head); 424 for (auto spair: node->nameToChildMap) { 425 if (std::regex_match(spair.first, r)) { 426 spair.second->collect(tail, list); 427 } 428 } 429 } else { 430 list.push_back(this); 431 } 432 } 433 } 434 } 435 } 436 return this; 437 } 438 439 440 JSonNode *JSonNode::get(std::string s, JSonNodeVisitor visitor) { 441 if (s == "") { 442 visitor(this); 443 } else { 444 auto slashpos = s.find_first_of('/'); 445 std::string head = (slashpos == std::string::npos) ? s : s.substr(0, slashpos); 446 std::string tail = (slashpos == std::string::npos) ? "" : s.substr(slashpos + 1); 447 if (head == "..") { 448 parent->get(tail, visitor); 449 } else { 450 if (head[0] == '{') { 451 auto eqpos = head.find_first_of('='); 452 auto tildepos = head.find_first_of('~'); 453 auto ccbracepos = head.find_last_of('}'); 454 auto notpos = head.find_first_of('!'); 455 if (eqpos != std::string::npos && (tildepos == std::string::npos || tildepos > eqpos) && ccbracepos != 456 std::string::npos && ccbracepos > eqpos) { 457 bool invert = (notpos != std::string::npos && notpos + 1 == eqpos); 458 std::string listName = head.substr(1, eqpos - 1 - (invert ? 1 : 0)); 459 std::string re = head.substr(eqpos + 1, ccbracepos - eqpos - 1); 460 JSonObjectNode *node = asObject(); 461 if (node) { 462 auto n = node->nameToChildMap[listName]; 463 if (n && n->isValue()) { 464 std::string svalue = n->asValue()->value; 465 if (invert && svalue != re) { 466 visitor(this); 467 } else if (!invert && svalue == re) { 468 visitor(this); 469 } 470 } 471 } 472 } else if (tildepos != std::string::npos && (eqpos == std::string::npos || eqpos > tildepos) && 473 ccbracepos != std::string::npos && ccbracepos > tildepos) { 474 bool invert = (notpos != std::string::npos && notpos + 1 == tildepos); 475 std::string listName = head.substr(1, tildepos - 1 - (invert ? 1 : 0)); 476 std::string re = head.substr(tildepos + 1, ccbracepos - tildepos - 1); 477 JSonObjectNode *node = asObject(); 478 if (node) { 479 auto n = node->nameToChildMap[listName]; 480 if (n && n->isValue()) { 481 std::string svalue = n->asValue()->value; 482 std::regex r(re); 483 bool matched = std::regex_match(svalue, r); 484 if (invert && !matched) { 485 visitor(this); 486 } else if (!invert && matched) { 487 visitor(this); 488 } 489 } 490 } 491 } 492 } else { 493 auto osbracepos = head.find_first_of('['); 494 auto csbracepos = head.find_last_of(']'); 495 if (osbracepos != std::string::npos && csbracepos != std::string::npos && csbracepos > osbracepos) { 496 // we have something akin to map[...] 497 std::string listName = s.substr(0, osbracepos); 498 std::string listSuffix = s.substr(osbracepos + 1, csbracepos - osbracepos - 1); 499 JSonObjectNode *node = asObject(); 500 if (node) { 501 std::regex r(listName); 502 for (auto spair: node->nameToChildMap) { 503 if (std::regex_match(spair.first, r)) { 504 if (tail == "") { 505 spair.second->get(listSuffix, visitor); 506 } else { 507 spair.second->get(listSuffix + "/" + tail, visitor); 508 } 509 } 510 } 511 } 512 } else { 513 // auto ocbracepos = s.find_first_of('{'); 514 JSonObjectNode *node = asObject(); 515 if (node) { 516 std::regex r(head); 517 for (auto spair: node->nameToChildMap) { 518 if (std::regex_match(spair.first, r)) { 519 spair.second->get(tail, visitor); 520 } 521 } 522 } else { 523 visitor(this); 524 } 525 } 526 } 527 } 528 } 529 return this; 530 } 531 532 JSonObjectNode *JSonObjectNode::remove(JSonNode *n) { 533 nameToChildMap.erase(n->name); 534 for (auto i = childArray.begin(); i != childArray.end(); i++) { 535 if (*i == n) { 536 childArray.erase(i); 537 break; 538 } 539 } 540 return this; 541 } 542 543 JSonObjectNode *JSonObjectNode::remove(std::string name) { 544 return remove(getNode(name)); 545 } 546 547 JSonObjectNode *JSonObjectNode::object(std::string name, JSonObjectNodeVisitor visitor) { 548 JSonObjectNode *newOne = new JSonObjectNode(this, name); 549 visitor(newOne); 550 add(newOne); 551 return this; 552 } 553 554 JSonObjectNode *JSonObjectNode::list(std::string name, JSonListNodeVisitor visitor) { 555 JSonListNode *newOne = new JSonListNode(this, name); 556 visitor(newOne); 557 add(newOne); 558 return this; 559 } 560 561 JSonObjectNode *JSonListNode::item(JSonObjectNodeVisitor visitor) { 562 JSonObjectNode *newOne = new JSonObjectNode(this, std::to_string(childArray.size())); 563 visitor(newOne); 564 add(newOne); 565 return this; 566 } 567 568 JSonObjectNode *JSonObjectNode::boolean(std::string name, std::string value) { 569 JSonValueNode *newOne = new JSonValueNode(this, name, BOOLEAN, value); 570 add(newOne); 571 return this; 572 } 573 574 JSonObjectNode *JSonObjectNode::boolean(std::string name, bool value) { 575 JSonValueNode *newOne = new JSonValueNode(this, name, BOOLEAN, std::to_string(value)); 576 add(newOne); 577 return this; 578 } 579 580 JSonObjectNode *JSonObjectNode::string(std::string name, std::string value) { 581 JSonValueNode *newOne = new JSonValueNode(this, name, STRING, value); 582 add(newOne); 583 return this; 584 } 585 586 JSonObjectNode *JSonObjectNode::integer(std::string name, std::string value) { 587 JSonValueNode *newOne = new JSonValueNode(this, name, INTEGER, value); 588 add(newOne); 589 return this; 590 } 591 592 JSonObjectNode *JSonObjectNode::integer(std::string name, int value) { 593 JSonValueNode *newOne = new JSonValueNode(this, name, INTEGER, std::to_string(value)); 594 add(newOne); 595 return this; 596 } 597 598 JSonObjectNode *JSonObjectNode::number(std::string name, std::string value) { 599 JSonValueNode *newOne = new JSonValueNode(this, name, NUMBER, value); 600 add(newOne); 601 return this; 602 } 603 604 JSonObjectNode *JSonListNode::boolean(std::string value) { 605 JSonValueNode *newOne = new JSonValueNode(this, std::to_string(childArray.size()), ValueType::BOOLEAN, value); 606 add(newOne); 607 return this; 608 } 609 610 JSonObjectNode *JSonListNode::boolean(bool value) { 611 JSonValueNode *newOne = new JSonValueNode(this, std::to_string(childArray.size()), ValueType::BOOLEAN, 612 std::to_string(value)); 613 add(newOne); 614 return this; 615 } 616 617 JSonObjectNode *JSonListNode::integer(std::string value) { 618 JSonValueNode *newOne = new JSonValueNode(this, std::to_string(childArray.size()), ValueType::INTEGER, value); 619 add(newOne); 620 return this; 621 } 622 623 JSonObjectNode *JSonListNode::integer(int value) { 624 JSonValueNode *newOne = new JSonValueNode(this, std::to_string(childArray.size()), ValueType::INTEGER, 625 std::to_string(value)); 626 add(newOne); 627 return this; 628 } 629 630 JSonObjectNode *JSonListNode::number(std::string value) { 631 JSonValueNode *newOne = new JSonValueNode(this, std::to_string(childArray.size()), ValueType::NUMBER, value); 632 add(newOne); 633 return this; 634 } 635 636 bool JSonNode::write(std::ostream o) { 637 JSonWriter w(o); 638 w.write(this, nullptr); 639 return true; 640 } 641 642 bool JSonNode::write(std::string filename) { 643 std::ofstream all(filename, std::ios::trunc); 644 JSonWriter w(all); 645 w.write(this, nullptr); 646 all.close(); 647 return true; 648 } 649 650 651 JSonObjectNode *JSonListNode::string(std::string value) { 652 JSonValueNode *newOne = new JSonValueNode(this, std::to_string(childArray.size()), ValueType::STRING, value); 653 add(newOne); 654 return this; 655 } 656 657 JSonObjectNode *JSonListNode::list(JSonListNodeVisitor visitor) { 658 JSonListNode *newOne = new JSonListNode(this, std::to_string(childArray.size())); 659 add(newOne); 660 visitor(newOne); 661 return this; 662 } 663 664 665 JSonWriter *JSonWriter::write(JSonNode *n) { 666 return write(n, nullptr); 667 } 668 669 JSonWriter *JSonWriter::write(JSonNode *n, Filter filter) { 670 if (filter == nullptr || filter(n)) { 671 if (n->isObject()) { 672 JSonObjectNode *object = n->asObject(); 673 obrace(); 674 in(); 675 nl(); 676 bool first = true; 677 for (auto c: object->childArray) { 678 if (filter == nullptr || filter(c)) { 679 if (first) { 680 first = false; 681 } else { 682 comma(); 683 nl(); 684 } 685 name(c->name); 686 write(c, filter); 687 } 688 } 689 out(); 690 nl(); 691 cbrace(); 692 } else if (n->isList()) { 693 JSonListNode *list = n->asList(); 694 osbrace(); 695 in(); 696 nl(); 697 bool first = true; 698 for (auto c: list->childArray) { 699 if (first) { 700 first = false; 701 } else { 702 comma(); 703 if (!c->isObject()) { 704 nl(); 705 } 706 } 707 write(c, filter); 708 } 709 out(); 710 nl(); 711 csbrace(); 712 } else if (n->isValue()) { 713 JSonValueNode *value = n->asValue(); 714 if (value->valueType == JSonNode::ValueType::STRING) { 715 oquote(); 716 } 717 std::size_t n = value->value.length(); 718 std::string escaped; 719 escaped.reserve(n * 2); // pessimistic preallocation 720 721 for (std::size_t i = 0; i < n; ++i) { 722 switch (value->value[i]) { 723 case '\n': 724 escaped += "\\n"; 725 break; 726 case '"': 727 escaped += "\\\""; 728 break; 729 case '\\': 730 escaped += "\\\\"; 731 break; 732 case '\r': 733 escaped += "\\r"; 734 break; 735 case '\t': 736 escaped += "\\t"; 737 break; 738 default: 739 escaped += value->value[i]; 740 break; 741 } 742 } 743 put(escaped); 744 if (value->valueType == JSonNode::ValueType::STRING) { 745 cquote(); 746 } 747 } else { 748 std::cerr << "what type is this!" << std::endl; 749 } 750 } 751 return this; 752 } 753 754 JSonWriter::JSonWriter(std::ostream &o) 755 : o(o), indent(0) { 756 } 757 758 JSonWriter *JSonWriter::put(std::string s) { 759 o << s; 760 return this; 761 } 762 763 JSonWriter *JSonWriter::comma() { 764 return put(","); 765 } 766 767 JSonWriter *JSonWriter::nl() { 768 o << std::endl; 769 std::fill_n(std::ostream_iterator<char>(o), indent, ' '); 770 return this; 771 } 772 773 JSonWriter *JSonWriter::in() { 774 indent++; 775 return this; 776 } 777 778 JSonWriter *JSonWriter::out() { 779 indent--; 780 return this; 781 } 782 783 JSonWriter *JSonWriter::colon() { 784 return put(":"); 785 } 786 787 JSonWriter *JSonWriter::oquote() { 788 return put("\""); 789 } 790 791 JSonWriter *JSonWriter::cquote() { 792 return put("\""); 793 } 794 795 JSonWriter *JSonWriter::obrace() { 796 return put("{"); 797 } 798 799 JSonWriter *JSonWriter::cbrace() { 800 return put("}"); 801 } 802 803 JSonWriter *JSonWriter::osbrace() { 804 return put("["); 805 } 806 807 JSonWriter *JSonWriter::csbrace() { 808 return put("]"); 809 } 810 811 JSonWriter *JSonWriter::name(std::string n) { 812 return oquote()->put(n)->cquote()->colon(); 813 } 814 815 JSonObjectNode *JSon::create(std::function<void(JSonObjectNode *)> builder) { 816 JSonObjectNode *root = new JSonObjectNode(nullptr, ""); 817 builder(root); 818 return root; 819 } 820 821 822 JSonNode *JSon::parseFile(std::string filename) { 823 if (fsutil::isFile(filename)) { 824 struct stat st; 825 stat(filename.c_str(), &st); 826 if (S_ISREG(st.st_mode)) { 827 int fd = ::open(filename.c_str(), O_RDONLY); 828 char *memory = new char[st.st_size]; 829 size_t bytesRead = 0; 830 size_t bytes = 0; 831 while (bytesRead < st.st_size && (bytes = ::read(fd, memory + bytesRead, st.st_size - bytesRead)) >= 0) { 832 bytesRead -= bytes; 833 } 834 ::close(fd); 835 JSonNode *json = JSonNode::parse(memory); 836 delete []memory; 837 return json; 838 } else { 839 std::cout << "not reg file!" << std::endl; 840 } 841 } 842 843 return nullptr; 844 }