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 }