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 }